Skip to main content

Full text of "Z-80 and 8080 assembly language programming"

See other formats


1     10001111     0f 110001  ^1101%0     01100^1     01101011  % 


LI  10001111  0T 110001 

®  10000011  00001100 

LI  11101111  11011111 

LI  00000001  10000111 


1001j^lll 
10001111 

10001111 y 
10001110 
000101211 
11110000 

11111000 
00000101 
10001010 
10li2ll010 
11010101 
00101011 

10001111 
11100000 
10001110 
00011111 
10001010. 


10000111 
00011110 
10101011 
10001101 
10001110 
00011100 

11010101 
10101010 
10001010 
01010010 
00010101 
01110101 

10/01000 
10000000 
10001111 

10001111 

00101010 


'01101T00 
01000011 
10111 Lll 
01010100 

1015^1110 
10000111 
10000111 
10001111 
00010101 
00011100 

10101010 
11111000 
01010100 
10101110 
11100011 
10001010 

10001101 
11000000 
10000011 
00011111 
10001010 


01000011  10000011  1S2 

11111101  11111110  IJ^ 

10001111  00001111  ly 

10001111  00010111  0j2 

10001111  10101011  0;^ 

10111111  10010101  01 

01001(^10  10000J01  1^ 

10000011  00000111  00 

11100011  10001110  111 


IQiK/jl/M     l|Wl(^lJ2f  1)^ 

IIAYI3KX  ^000101  1)^ 

fcSTlZJTTOZ^  Wi010100  0^ 

10000011     00010101  i;i 

00101000     11000101  lO; 

11100010     10001010  00 


11100011 
11100000 
00001111 
01010000 
10001010 


10101000 
10000000 
01111110 
10000111 
10001111 


Digitized  by  the  Internet  Archive 

in  2014 


https://archive.org/details/z808080assemblyl00kath 


Z-80  and  8080 
Assembly  Language 
Programming 


Hayden  Computer  Programming  Series 


BASICS  OF  DIGITAL  COMPUTER  PROGRAMMING  (Second  Ed.) 
John  S.  Murphy 

BASIC  BASIC:  An  Introduction  to  Computer  Programming  in  BASIC  Language  (Second  Ed.) 
James  S.  Coan 

ADVANCED  BASIC:  Applications  and  Problems 
James  S.  Coan 

DISCOVERING  BASIC:  A  Problem  Solving  Approach 
Robert  E.  Smith 

PROGRAMMING  PROVERBS 
Henry  F.  Ledgard 

PROGRAMMING  PROVERBS  FOR  FORTRAN  PROGRAMMERS 
Henry  F.  Ledgard 

FORTRAN  WITH  STYLE:  Programming  Proverbs 
Henry  F.  Ledgard  and  Louis  J.  Ciimura 

COBOL  WITH  STYLE:  Programming  Proverbs 
Louis  J.  Chmura  and  Henry  F.  Ledgard 

BASIC  WITH  STYLE:  Programming  Proverbs 
Paul  A.  Nagin  and  Henry  F.  Ledgard 

PASCAL  WITH  STYLE:  Programming  Proverbs 
Henry  F.  Ledgard  and  Paul  A.  Nagin 

FORTRAN  FUNDAMENTALS:  A  Short  Course 
Jack  Stelngraber 

THE  BASIC  WORKBOOK:  Creative  Techniques  for  Beginning  Programmers 
Kenneth  E.  Schoman,  Jr. 

BASIC  FROM  THE  GROUND  UP 
David  E.  Simon 

APL:  AN  INTRODUCTION 
Howard  A.  Peelie 

Z-80  AND  8080  ASSEMBLY  LANGUAGE  PROGRAMMING 
Kathe  Spracl<len 


1 


Z-80  and  8080 
Assembly  Language 
Programming 


KATHE  SPRACKLEN 


HAYDEN  BOOK  COMPANY.  INC. 
Rochelle  Park,  New  Jersey 


To  my  precious  stepdaughters 
Teresa  and  Amy 


ISBN  0-8104-5167-0 

Library  of  Congress  Catalog  Card  Number  79-65355 

Copyright  ©  1979  by  HAYDEN  BOOK  COMPANY,  INC.  All  rights  reserved. 
No  part  of  this  book  may  be  reprinted,  or  reproduced,  or  utilized  In  any 
form  or  by  any  electronic,  mechanical,  or  other  means,  now  known  or 
hereafter  invented,  including  photocopying  and  recording,  or  in  any  infor- 
mation storage  and  retrieval  system,  without  permission  in  writing  from 
the  Publisher. 

Printed  in  the  United  States  of  America 

123456789  PRINTING 
79   BO  81    82   83   84   85  86  87  YEAR 


Preface 


My  first  concern  was  chess.  The  dream  was  and  is  to  create  a  microcom- 
puter program  that  can  play  chess  at  the  master  level.  But  computer  chess 
could  not  be  done  effectively  using  BASIC.  It  had  to  be  assembly  language. 
For  Dan  and  me  learning  and  using  Z-80  assembly  language  posed  no  prob- 
lem because  of  our  prior  background  writing  in  other  assembly  level  lan- 
guages. But  we  wanted  also  to  share  what  we  had  done  in  creating  SARGON, 
and  for  many  potentially  gifted  programmers  there  seemed  to  be  a  desperate 
lack  of  suitable  introductory  material.  I  was  especially  concerned  with  texts 
that  insult  the  intelligence  of  the  reader.  Yet  among  those  written  for  the 
capable  layman  there  seemed  to  be  a  heavy  emphasis  on  the  hardware  aspects 
of  microprocessors.  What  I  wanted  to  see  was  a  book  that  taught  Z-80  assem- 
bly language  as  a  first  assembly  language;  a  book  that  emphasized  software 
and  covered  the  xises  of  the  machine  instructions  in  tackling  a  programming 
project.  This  book  was  written  to  fill  that  need. 

In  creating  this  book  I  owe  a  double  debt  to  Professor  David  Solomon, 
San  Diego  State  University.  Dr.  Solomon  provided  me  with  my  first  introduc- 
tion to  assembly  language  and  later  to  microcomputers.  In  his  classes  I  en- 
joyed the  delicious  dawning  of  understanding  of  just  what  a  computer  is  and 
does.  I  thank  my  students  at  The  Computer  Center,  Ronson  Rd.,  San  Diego, 
for  their  comments  and  suggestions  on  the  first  draft  of  this  book,  particularly 
Arthur  Wolman.  To  my  husband,  Dan,  go  many  thanks  for  giving  me  the 
computer  "bug"  in  the  first  place  and  for  leading  the  way  in  computer  chess. 
Finally  I  would  like  to  thank  my  mother,  Margaret  Shannon,  and  my  grand- 
mother, Julia  Dumas,  for  providing  two  generations  of  creative,  competent 
women  to  admire  and  emulate. 

Kathe  Spracklen 

San  Diego 


Contents 


Introduction   1 

Bits,  Bytes,  and  Boolean  Operators   4 

Where  Is  My  Variable?    14 

A  Method  to  Our  Logic    31 

Jumps,  Loops,  and  Modular  Programming    43 

Bit  Fiddling  and  Message  Making   57 

A  Casual  Introduction  to  Data  Structures   71 

Binary  Coded  Decimal  Arithmetic   83 

When  Time  Is  Important   96 

Appendix  A:  8080/Z-80  Conversion  Chart 

and  Instruction  Summary  103 

Appendix  B:  ASCII  Code  Summary   113 

Appendix  C:  8080  Disassembler  114 

Appendix  D:  Z-80  Extension  Disassembler  119 

Appendix  E:  Answers  to  Exercises  125 

Index   166 


I 


introduction 


Are  you  bored  with  BASIC? 

Do  your  photon  torpedoes  drift  listlessly  across  your  screen? 
Does  it  take  ages  to  age  your  accounts  receivable? 

Maybe  you're  ready  to  tackle  assembly  language  programming.  If  so,  this  is 
the  place  to  start.  This  book  assumes  that  you  know  a  little  bit  about  com- 
puters and  have  done  some  programming  in  a  higher  level  language  like 
BASIC  or  FORTRAN.  It  assumes  familiarity  with  words  like 

VARIABLE 
GOTO 
LOOP 
ARRAY 

The  approach  is  designed  for  the  novice  to  assembly  programming  and  is 
intended  to  provide  just  about  everything  the  applications  programmer  needs 
to  know  to  get  the  most  out  of  his  machine.  Some  topics  are  conspicuously 
omitted,  since  they  are  really  relevant  only  to  someone  designing  a  monitor 
program  or  operating  system.  The  emphasis  here  is  to  give  the  user  all  the 
information  needed  to  interact  with  his  monitor. 

Here  are  some  of  the  features  that  make  this  book  unique. 

•  Each  concept  and  instruction  is  carefully  explained. 

•  Numerous  diagrams  and  examples  are  provided. 

•  Exercises  designed  to  instruct  and  challenge  you  are  included  with  each 
chapter,  and  answers  to  each  are  provided. 

•  Programming  techniques  are  presented  along  with  the  instructions. 

There  are  eight  chapters  in  this  book.  Each  chapter  gradually  builds  on  the 
work  of  preceding  ones.  The  exercises  are  a  part  of  the  instructional  material 
as  well.  Do  try  them.  They  will  help  you  quickly  develop  your  skills  as  an 
assembly  language  programmer,  as  most  exercises  ask  you  to  write  segments 
of  code.  When  you  turn  to  the  answers,  however,  please  remember  that  what 
you  see  is  but  one  possible  way  of  doing  things.  It  is  very  unlikely  that  we  will 


1 


2 


Z-8B  and  8B8B  Assembly  Language  Programming 


agree  totally  on  the  approach  to  take,  so  to  check  your  work  try  it  out  on  your 
computer. 

Assembly  programming  is  really  worth  the  effort  it  takes  when  you're 
new  at  it.  Later,  when  you  become  comfortable  with  the  instructions,  it  is 
only  slightly  more  difficult  than  BASIC.  In  return  it  gives  you 

•  complete  control  of  your  system 

•  flexibility  in  the  management  of  your  data 

•  speedier  execution 

•  compact  programs 

Then,  too,  there's  that  delicious  sense  of  satisfaction  when  you  can  say:  "No, 
it's  not  in  BASIC.  I  wrote  it  in  assembly  language." 

The  programs  we  will  write  in  assembly  language  are  much  different 
than  programs  written  in  BASIC.  Each  line  of  a  BASIC  program  is  translated 
by  another  program  (called  a  BASIC  interpreter)  into  several  lines  of  assem- 
bly level  code.  An  example  will  serve  to  illustrate  this  one-to-many  transla- 
tion. Suppose  we  write  an  algebraic  statement  in  BASIC:  Z  =  X  +  Y.  Let's 
see  the  assembly  level  statements  that  could  be  used  to  accomplish  this. 

1.  Go  get  the  value  of  X  and  place  it  in  the  accumulator.  (The  ac- 
cumulator is  the  spot  where  the  addition  will  take  place.) 

2.  Set  up  a  pointer  to  the  location  where  the  value  of  Y  is  stored. 

3.  Add  the  accumulator  contents  to  the  value  the  pointer  locates.  (The 
sum  will  be  left  in  the  accumulator.) 

4.  Store  the  contents  of  the  accumulator  in  the  location  belonging  to  Z. 

The  assembly  level  statements  are  the  closest  to  the  actual  computer  actions 
that  a  programmer  may  specify.  Each  statement  written  in  assembly  language 
is  translated  by  another  program  (called  an  assembler)  into  one  machine 
instruction. 

All  machine  instructions  are  strings  of  0s  and  Is.  One  example  is 

10111000 

Now  this  may  make  perfect  sense  to  a  computer,  but  humans  tend  to  think 
better  in  words.  This  is  where  assembly  language  comes  in.  It  allows  the 
programmer  to  refer  to  the  instructions  in  word- like  abbreviations  called 
mnemonics. 

In  this  text  we  will  be  studying  most  of  the  instructions  available  to  the 
programmer  of  the  Z-80  microprocessor.  In  each  case  we  will  learn 

1 .  how  the  instruction  works 

2 .  the  mnemonic 

3.  the  machine  code  (OP  code) 


Introduction 


3 


The  job  of  the  assembly  language  programmer  is  to  know  how  the  in- 
structions can  do  the  job  he  needs  done  and  to  write  the  instruction 
mnemonics.  The  job  of  the  assembler  program  is  to  translate  the  mnemonics 
into  machine  code.  The  job  of  the  computer  is  to  execute  the  machine  code 
instructions.  Two  other  programs  may  be  involved  in  this  process.  A  text 
editor  program  is  usually  used  to  write  the  mnemonics  into  a  text  file,  usually 
maintained  on  a  tape  or  disk  system.  A  load  program  (or  loader)  is  used  to 
input  the  machine  code  (often  called  an  object  file)  into  the  computer's 
memory  for  execution.  The  whole  process  can  be  summarized  as  follows. 


Programmer 
designs  program  and 
writes  mnemonics. 


Programmer  keys 
mnemonics  in  using 
text  editor  program. 
He  creates  a  text  file 
in  computer  memory  or 
on  tape  or  disk. 


Assembler  program 
translates  mnemonics  into 
machine  code  and  creates 
an  object  file  in  computer 
memory  or  on  tape  or  disk. 


Loader  program  brings  Programmer  runs 

object  file  into  program  for  testing 

computer  for  execution.  and  debugging. 


The  emphasis  in  this  text  is  on  the  steps  of  design  and  coding.  Running 
the  text  editor,  assembler,  and  loader  is  just  a  matter  of  following  the  specific 
instructions  included  with  the  particular  versions  running  on  your  system. 
Some  specific  help  on  how  to  debug  your  programs  can  be  found  in  the  final 
chapter  of  this  book. 


bits,  bytes,  and 
boolean  operators 


Binary  and  Hexadecimal  Number  Systems 

The  binary  number  system  is  the  basis  of  computer  operations.  It  requires  the 
use  of  only  two  digits:  0  and  1.  These  two  possibiHties  can  be  easily 
represented  by  a  low  and  high  voltage,  respectively.  The  decimal  numbers  0 
through  5  appear  below  written  in  binary  form. 

0  =  0 

1  =  1 

10  =  2 

11  =  3 

100  =  4 

101  =  5 

It  can  be  seen  that  the  numbers  rapidly  become  very  long. 

In  the  decimal  system  each  digit  represents  a  power  of  10.  For  example 

423  =  4  X  100  =  4  X  102 
+  2  X  10  +  2  X  10' 
+  3x1         +  3  X  100 

(Any  number  raised  to  the  0  power  is  1 .  So,  2"  =  1 ,  10"  =  1 ,  and  16"  =  1 .) 
In  the  binary  system,  each  digit  represents  a  power  of  2. 

1101 =  1  X  2'  =  1x8 
+  1  X  22  +1x4 
+  0x2^  +0x2 
+  1x2"  +1x1 

So  1101  in  binary  is  the  equivalent  of  13  in  decimal.  Conversion  between  the 
two  number  systems  can  be  done  using  these  rules,  but  it  is  not  common  to 
have  to  convert  numbers  larger  than  15  back  and  forth.  Larger  numbers  are 
generally  first  converted  into  the  hexadecimal  system. 

In  the  hexadecimal,  or  base  16,  number  system,  there  are  16  different 
digits.  The  digits  0-9  are  borrowed  from  the  decimal  system,  and  letters  of 
the  alphabet  fill  in  for  the  other  six. 


4 


Bits,  Bytes,  and  Boolean  Operators 


5 


A  = 

10 

B  = 

11 

C  = 

12 

D  = 

13 

E  = 

14 

F  = 

15 

In  the  hexadecimal  system,  each  digit  represents  a  power  of  16. 

1B3  =     1  X  162  =       IX  256 
+  B  X  16'     +  11  X  16 
+  3  X  16"  +3x1 

So  1B3  (hexadecimal)  is  the  equivalent  of  435  in  the  decimal  system. 

With  three  number  systems  in  use,  some  way  to  distinguish  between  them 
is  necessary.  Whenever  confusion  could  arise,  we  will  use  a  subscripted  letter 
to  distinguish  between  the  systems. 

10j^  —  Hexadecimal 
10Q  —  Decimal 
10g  —  Binary 

Converting  Between  the  Systems 

Conversions  of  small  numbers  can  be  done  using  the  following  chart. 


Decimal  Binary  Hexadecimal 

0  0  0 

1  1  1 

2  10  2 

3  113 

4  100  4 

5  101  5 

6  110  6 

7  111  7 

8  1000  8 

9  1001  9 

10  1010  A 

11  1011  B 

12  1100  C 

13  1101  D 

14  1110  E 

15  1111  F 

16  10000  10 


6 


Z-80  and  8080  Assembly  Language  Programming 


Hexadecimal-Decimal 

Hexadecimal  numbers  can  be  converted  into  the  decimal  system  most  easily 
by  using  the  powers  of  16.  The  following  example  shows  how  to  convert 
2AF3jj  to  decimal. 

2  X  16»  =  2  X  4096  =  8192  =  10,995^, 

+  A  X  16*  +  10  X    256  +  2560 

+  F'x  16°  +  15  X     16  +  240 

+  3xl6»  +3x1  +3 

Conversions  from  decimal  to  hexadecimal  can  be  done  using  division  and 
the  following  chart  of  powers  of  1 6 . 

Powers  of  1 6 

16«  =  1 
16>  =  16 
162  =  256 
16^  =  4,096 
16*  =  65,536 

Numbers  larger  than  16*  are  rarely  encountered.  We  will  always  begin  by 
dividing  by  the  largest  power  of  16  that  will  fit.  Beginning  with  10,995jj, 
here's  how  to  get  back  to  2AF3j^. 

2  r  2803 


4096  I  10,995 

10  r  243 
256  I  2803 


15r  3 


16  I  243 


3 

1  IT"  3 


Hexadecimal- Binary 

Conversions  between  hexadecimal  and  binary  are  extremely  easy.  Every 
hexadecimal  digit  can  be  translated  into  four  binary  digits  using  the  con- 
version chart.  For  example, 

53Dh  =  101    0011  1101b 

Binary  numbers  can  be  converted  to  hexadecimal  by  counting  off  groups 
of  four  digits  beginning  from  the  right.  Then  each  group  is  translated  into  a 
hexadecimal  digit.  Thus, 


Bits,  Bytes,  and  Boolean  Operators 


1011101101b  =  10  1101b  =2EDh 


Bits  and  Bytes 

A  bit  is  the  unit  of  storage  required  to  hold  one  binary  digit.  We  will  denote  a 
bit  by  enclosing  the  0  or  1  value  in  a  box  as  shown. 

m 


0 


or 


Sometimes  bits  are  important  in  themselves,  but  usually  they  are  con- 
sidered in  groups.  A  group  of  eight  bits  is  called  a  byte.  We  v^ll  denote  a 
byte  as  a  string  of  eight  boxes. 


0   10   0  10 


1 


Since  four  bits  make  one  hexadecimal  digit,  it  takes  two  hexadecimal  digits  to 
describe  the  contents  of  a  byte.  Sometimes  a  group  of  four  bits  is  called  a 
nibble. 

The  byte  is  the  basic  arithmetic  unit  of  a  microcomputer.  If  we  only  want 
to  count,  the  highest  number  we  can  count  to  in  a  byte  is  255. 


1 

1 

1 

1 

1 

1 

1 

1 

=  FF. 


255. 


We  also  have  the  capability  of  adding  two  positive  numbers,  so  long  as  they  do 
not  total  more  than  255.  But  how  can  we  subtract?  Subtraction  requires  the 
ability  to  express  negative  numbers. 


2's  Complement  Representation 

We  would  like  to  have  the  ability  to  represent  negative  as  well  as  positive 
numbers.  This  is  accomplished  by  reserving  one  of  the  eight  bits  as  an  in- 
dicator of  the  sign  of  the  number. 


x 

x 

X 

X 

X 

X 

X 

I  X 

x 

X 

X 

X 

X 

X 

Positive  (0  sign  bit) 
Negative  (1  sign  bit) 


By  tying  up  one  of  the  eight  bits  to  indicate  the  sign,  we  are  left  with  only 
seven  bits  for  the  magnitude  of  the  number.  So  the  highest  number  we  can 
count  to  is  127. 


0 

1 

1 

1111 

1 

So  how  would  we  represent  -  127?  A  first  try  might  be  to  simply  reverse  the 
sign  bit  and  leave  all  the  magnitude  bits  unchanged.  Although  this  scheme  is 
easy  to  understand,  it  turns  out  to  be  very  difficult  to  work  with. 

A  second  try  might  be  to  reverse  all  the  bits.  This  is  called  I's  com- 
plement. 


8 


Z-80  and  8080  Assembly  Language  Programming 


0 

0 

0 

1  1 

0 

0 

1 

1  1 

0 

0 

1 

0 

1 

=  26 


D 


=  I's  complement  of  26 


If  we  used  this  method  to  represent  negative  numbers,  let's  see  where  it  would 
lead.  We  would  certainly  want  26  and  -  26  to  add  up  to  zero.  But 


+ 


0 

0  0 

1 

1 

0 

1 

0 

1 

1  1 

0 

0 

1 

0 

1 

11111 

1  1 

1 

when  we'd  really  like  all  0s.  However,  if  we  add  1  and  ignore  the  carry,  we  get 
just  what  we  want: 


1 

1 

1 

1 

1 

1 

1 

+  |0 

0 

0 

0 

0 

0  1 

carry 


|0 

0 

0 

0 

0 

0 

0 

Out  of  this  reasoning  came  2's  complement  representation  of  negative 
numbers.  2's  complement  is  formed  by  adding  1  to  the  I's  complement  form. 


+ 


0 

0 

0 

1 

1 

0 

1 

0 

=  26^ 

1 

1 

1 

0 

0 

1  0 

1 

=  I's  complement  of  26 

0 

0  0 

0 

0 

0 

0 

1 

1 

1 

1 

0 

0 

1 

1 

0 

0      =  2's  complement  of  26 


Converting  a  negative  number  back  to  positive  can  be  done  using  the  exact 
same  steps. 


1 

1 

1 

0 

0 

1 

1 

0 

0 

0 

0 

1 

1  0 

0  1 

0 

0 

0 

0 

0 

0 

0 

1 

0 

0 

0 

1 

1 

0 

1 

0 

=  -27, 


=  I's  complement  of  —  26 


=  26 


D 


Byte-Size  Arithmetic 

We  are  now  equipped  to  perform  addition  and  subtraction  of  binary  num- 
bers. Here  are  some  examples. 


Bits,  Bytes,  and  Boolean  Operators 


11 

0 

0 

0 

0 

1 

0  1 

1 

11 


0 

0 

0 

0 

1 

0|l 

1 

+  7+00 

0 

0 

0 

1  1 

1 

-7 

0 

0 

0 

0 

0 

1 

1 

1 

18 

0 

0 

0  1 

0 

0 

1  0 

4 

0 

0 

0 

0 

0 

1 

0 

0 

Arithmetic  Flags 


We  have  already  seen  one  of  the  arithmetic  flags,  the  carry  flag.  It  is  set 
whenever  the  result  of  an  addition  is  larger  than  eight  bits. 


1 

0 

0 

0 

0 

0 

0 

0 

1 

+  (-1)  + 

1 

1 

1 

1 

1 

1 

1 

0       carry  [Tl 

0 

0 

0 

0  0 

0 

0 

0 

In  addition  the  carry  bit  is  most  often  just  ignored.  It  is  simply  a  by-product  of 
2's  complement  representation. 

In  subtraction  the  carry  bit  has  more  meaning. 


1     carry  [T|    1  0 

0 

0 

0 

0 

0 

0 

1 

2                  -  0 

0 

0 

0 

0 

0  1 

0 

1  1 

1 

1 

1 

1  1 

1 

1 

Here  it  is  when  a  borrow  is  generated.  Thus  the  carry  bit  tells  us  that  we 
subtracted  a  number  from  a  smaller  number. 

The  overflow  flag  is  an  indication  that  something's  gone  wrong.  We 
know  that  an  eight  bit  number  with  one  sign  bit  and  seven  magnitude  bits 
cannot  be  larger  than  127.  The  smallest  it  can  be  is  —  128. 


1 


0000000      =-  128 


Now  suppose  we  try  to  add  75  and  80: 
75 


0  10  0  10 


+  80 


+    0   10   1   0  0   0  0 


155 


0  0 


0 


10 


Z-Sdand  8080  Assembly  Language  Programming 


What  has  happened  is  that  the  magnitude  bits  have  carried  over  into  the  sign 
bit,  making  the  result  look  like  a  negative  number.  The  overflow  flag  is  then 
set  to  indicate  that  the  answer  is  unreliable.  This  can  also  happen  when  two 
large  negative  numbers  are  added.  The  overflow  flag  is  again  set  to  point  up 
the  trouble. 


(-75) 


10   110    10  1 


+  (-80)  + 

I— ( 

0 

1 

1 

0 

0 

0 

0 

-155  [T| 

0 

1 

1 

0 

0  1 

0  1 

Again  the  sign  bit  was  reversed.  The  carry  flag  was  also  set,  but  that  is 
unimportant. 

If  the  two  operands  to  be  added  are  of  opposite  sign,  no  overflow  can 
occur. 

Two  other  flags  are  very  simple  in  their  operation.  The  sign  flag  in- 
dicates whether  the  result  of  an  arithmetic  operation  is  positive  or  negative.  It 
is  an  exact  copy  of  the  sign  bit,  so  0  means  the  result  was  positive  and  1  in- 
dicates a  negative  result.  Since  a  zero  result  has  a  0  sign  bit,  it  is  obviously 
considered  to  be  a  positive  number.  A  zero  result,  however,  is  so  important 
that  it  is  reported  in  a  flag  all  its  own.  The  zero  flag  is  set  when  the  result  is 
zero. 


Summary  of  Eight  Bit  Arithmetic  Flags 

Carry  (C)         —         Carry  out  of  the  eight  bits 

1 :  occurred 
0:  did  not  occur 

Overflow  (V)    —        Sign  bit  clobbered 

1 :  occurred 
0:  did  not  occur 

Sign  (S)  —         Result  was 

1 :  negative 
0:  positive 

Zero  (Z)  —        Zero  result 

1 :  occurred 

0:  did  not  occur 


Bits,  Bytes,  and  Boolean  Operators 


11 


Boolean  Operators 

Arithmetic  is  not  the  only  thing  that  can  be  done  to  pairs  of  eight  bit  values. 
There  is  the  whole  class  of  logical,  or  Boolean,  operators.  Boolean  operators 
treat  all  eight  bits  alike,  with  no  sign  bit. 


AND 

The  AND  operator  compares  two  bytes  bit  by  bit.  If  a  bit  is  set  in  both 
operands,  it  is  set  to  1  in  the  result.  Otherwise  the  bit  is  reset  to  0  in  the  result. 
This  operation  is  summarized  in  the  following  table. 


ABA  AND  B 


1  1  1 

1  0  0 

0  1  0 

0  0  0 


Usirg  this  table,  each  of  the  bits  in  a  byte  is  set  or  reset  in  turn,  as  in  the 
following  example. 


1 

1 

0 

0 

0 

0 

1 

1 

AND 

1 

0 

1 

0 

0 

1 

0 

1 

A 
B 


1 

0 

0 

0 

0 

0   0  1 

OR 

The  OR  operator  compares  two  bytes  bit  by  bit.  If  a  bit  is  set  in  either 
operand,  it  is  set  in  the  result.  Otherwise  it  is  reset  in  the  result. 


A 

B 

A  ORB 

1 

1 

1 

1 

0 

1 

0 

1 

1 

0 

0 

0 

1 

1 

0 

0 

0 

0 

1  1 

A 

OR 

1 

0   10  0    10  1 

B 

1  1 

1 

0 

0 

1    1  1 

A  ORB 

12 


Z-80and  8680  Assembly  Language  Programming 


XOR 

The  XOR  (exclusive  OR)  operator  compares  the  two  bytes  bit  by  bit.  If  the 
bit  is  set  in  either  operand,  but  not  in  both,  it  is  set  in  the  result.  Otherwise  it 
is  reset  in  the  result. 

A  B  AXORB 


1 
1 

0 
0 


1 
0 


0 
1 


1 

1 

0 

0 

1 

1 

0 

0 

0 

0 

1 

1 

XOR     10   10  0  1 


A 
B 


0 

1 

1 

0 

0 

1 

1  0 

0      A  XOR  B 


Flags  and  the  Binary  Operators 

Carry     -      Reset  by  AND,  OR,  and  XOR 

Zero       —      Indicates  that  all  bits  of  the  result  are  zero 

1 :  occurred 
0:  did  not  occur 


Sign       —      Set  to  the  value  in  the  uppermost  bit  (same  as 
arithmetic  operation) 

Logical  operations  affect  the  parity  flag  instead  of  the  overflow  flag.  The 
parity  flag  tells  whether  an  even  or  an  odd  number  of  bits  are  set  in  the  result. 
The  parity  flag  is  set  when  an  even  number  of  bits  are  set  in  the  result.  The 
flag  is  reset  when  an  odd  number  of  bits  are  set  in  the  result. 


Result 
Result 


0 


0    1  0 


P  =  0 


0  0  0  0   0  0 

P  =  1 


(five  bits  set) 
(two  bits  set) 


Exercises 


1 .  Convert  the  following  numbers  to  decimal. 

a.  101  e.  10000000 

b.  1101  f.  11001010 

c.  11101  g.  10001110 


101011 


11111001 


i.  00010010 

j.  01110011 

k.  111000100 

1.  1010101011 


1 


Bits,  Bytes,  and  Boolean  Operators 


13 


2.  Convert  the  following  decimal  numbers  to  hexadecimal  and  then  from 
hexadecimal  to  binary. 

a.  6  e.        542  i.  15,430 

b.  14  f.       1077  j.  43,751 

c.  127  g.      4095  k.  65,552 

d.  280  h.      8702  1.  70,980 

3.  Give  the  eight-bit  signed  representation  of  the  following  positive  numbers. 
Then  convert  each  to  2's  complement. 

a.  7  c.     23  e.  104 

b.  17  d.    48  f.  127 

4.  Given  the  following  bytes  with  one  sign  bit  and  seven  magnitude  bits,  give  the 
decimal  equivalent  of  their  contents. 


a.  0 

0 

0  0 

1 

0 

0 

1 

d. 

0 

0 

1 

0 

0 

1 

1 

1 

b. 


0  0  0   1    1   0  0 


110   0  10 


c. 


1 

1 

1 

1 

1 

0 

1 

1 

f. 


1 

1 

0  1 

0 

0 

0 

0 

5.  Perform  the  following  arithmetic  operations  in  binary  form.  For  each,  give 
the  result  in  binary,  and  tell  whether  the  carry  and/ or  overflow  flags  are  set. 

a.  11  +  15  d.  104  +  55 

b.  17  +  (-21)  e.  (-67)  -  107 

c.  46-12  f.    (-67)  +  107 

6.  For  each  of  the  following  pairs  of  bytes,  find  their  AND,  OR,  and  XOR. 
Indicate  what  flags  are  set. 


0 

0 

0 

0 

0 

0 

0 

0 

0  0 

0   10  0 

0 

0 

0   1  0 


0 


0  0 


0 


b. 


1 

1 

1 

1 

1 

1  1 

1 

f. 

1 

0 

0 

0 

0 

0 

0 

0 

1  0 

1  1 

0 

1 

0 

0 

0 

1 

1    1  0 

0  0 

1 

1 

1 

0 

1 

1 

1 

1 

1 

0 

0 

1 

1 

0 

1 

1 

0 

0 

1 

0 

1 

0 

1  0 

1 

1 

0 

1 

0 

1 

0  1 

0 

d. 

1 

1 

1 

1 

0 

1 

1 

1 

h.  1 

1 

0 

0 

1 

1 

1 

1 

1 

0 

1 

0 

0 

0 

1 

0 

1 

1 

0 

0 

1 

1 

1 

1 

where  is  my  variable? 


The  Higher  Level  Language  Programmer 

Whatever  else  the  higher  level  language  programmer  may  know  about  his 
program,  he  probably  has  very  little  sense  of  where  his  variables  are  located. 
Consider  the  following  program: 

X  =  3 
Y  =  2 
Z  =  X  +  Y 
PRINT  Z 

Where  is  X?  Where  is  Y?  Where  does  the  addition  take  place?  The  whole 
"where"  aspect  is  generally  quite  foreign  to  the  new  assembly  language 
programmer.  Also  missing  is  the  language  needed  to  talk  about  "where" 
topics. 


Registers 

The  registers  are  one  of  the  most  common  answers  to  a  "where"  question. 
Here  is  a  diagram  of  the  8080  register  set.  (The  Z-80  has  these  and  more.) 


A 

Flags 

B 

C 

D 

E 

H 

L 

Each  of  the  registers  is  eight  bits  long.  The  bits  are  numbered  from  right  to 
left.  All  of  the  registers  look  alike.  Here  is  a  close-up  of  one  of  the  registers. 


Bit#  76543210 


1 


0 


1 


0  10   10    Register  E 


The  A  register  is  the  answer  to  the  question:  "Where  does  the  addition 
take  place?"  Also  called  the  accimiulator,  register  A  always  holds  one  of  the 
two  operands  in  an  add,  subtract,  AND,  OR,  or  XOR  operation.  The  result 


14 


Where  Is  My  Variable? 


15 


is  also  left  in  register  A.  So  every  arithmetic  and  logical  operation  is  of  the 
form 

X-^X  A  Y 

The  register  labeled  "Flags"  is  where  the  carry,  overflow,  and  other  flag  bits 
are  stored.  It  is  usually  accessed  only  one  bit  at  a  time. 

Registers  B  and  C,  D  and  E,  and  H  and  L  may  be  treated  as  register 
pairs.  Then  the  two  eight  bit  registers  may  instead  be  regarded  as  one  16  bit 
register.  Besides  being  able  to  house  a  larger  number,  the  main  use  of  16  bit 
values  in  a  microcomputer  is  to  address  memory. 

Memory 

Memory  is  the  most  likely  answer  to  the  question  concerning  the  whereabouts 
of  any  variable.  It  also  answers  the  question  "Where  is  my  program?" 

Memory  is  divided  into  individual  bytes.  Each  byte  in  memory  has  a 
unique  address.  Addresses  in  the  8080  and  Z-80  are  all  two  bytes  in  length. 
How  much  memory  can  be  addressed  in  two  bytes?  Consider  the  following 
progression. 


#  of  Bits 

Size  of  Memory 

Highest  Address 
in  Hexadecimal 

8 

256  bytes  (0-255) 

FF 

9 

512  bytes 

IFF 

10 

1024  bytes  =  Ik 

3FF 

11 

2048  bytes  =  2k 

7FF 

12 

4096  bytes  =  4k 

FFF 

13 

8192  bytes  =  8k 

IFFF 

14 

16,384  bytes  =  16k 

3FFF 

15 

32,768  bytes  =  32k 

7  FFF 

16 

65,536  bytes  =  64k 

FFFF 

One  byte  addresses  only  allow  for  Y^k  of  memory.  Since  this  is  usually 
inadequate,  the  logical  choice  was  to  go  to  two  bytes  for  an  address.  A  two 
byte  address  allows  the  possibility  of  addressing  64k  of  memory. 

We  have  already  mentioned  that  the  BC,  DE,  and  HL  register  pairs  may 
be  used  to  contain  memory  addresses.  There  are,  in  addition,  two  other  16 
bit  memory  address  registers  common  to  the  8080  and  Z-80  microprocessors. 

Stack  Pointer  and  Program  Counter 

The  stack  pointer  (SP)  is  a  16  bit  register  whose  only  function  is  to  point  to  a 
location  in  memory. 


16  Z-80  and  8080  Assembly  Language  Programming 


3C04 


In  the  Z-80  microprocessor,  the  stack  is  just  a  designated  portion  of  regular 
memory.  The  programmer  sets  the  stack  to  the  location  of  his  choosing.  With 
the  question  "Where  is  the  stack?"  out  of  the  way,  a  good  question  to  consider 
next  is  "What  is  the  stack?" 

A  stack,  in  the  general  sense,  is  a  collection  of  items  where  all  additions 
and  all  deletions  occur  at  the  top.  A  stack  of  dishes,  for  example,  fits  this 
description. 


The  stack  Addition  to  Deletion  from 

the  stack  the  stack 


The  characteristic  of  a  stack  is  that  only  the  top  is  accessible. 

The  stack  in  the  Z-80  or  8080  sense  is  a  region  of  memory  where  values 
can  be  saved  temporarily.  Its  most  common  use  comes  in  relation  to 
subroutine  calls,  but  it  can  be  used  to  store  intermediate  results  in  a  com- 
putation, or  any  short-lived  variable.  Use  of  the  stack  for  these  purposes  saves 
having  to  use  a  separate,  unique  memory  location  for  transient  data. 

The  program  counter  is  also  a  16  bit  register  which  points  to  an  address 
in  memory.  That  address  is  located  within  the  program  that  is  currently 
running,  and  contains  the  next  instruction  to  be  executed. 


r 


Where  Is  My  Variable? 


17 


Notation 

Suppose  we  have  a  variable  located  in  memory  which  we  have  called  VAR- 
BLE.  Since  VARBLE  is  located  in  memory,  it  has  an  address.  It  also  has  a 
value.  So  when  we  use  VARBLE,  which  do  we  mean,  the  address  or  the  value? 
To  the  higher  level  language  programmer  there  can  be  no  problem.  He  knows 
nothing  of  the  whereabouts  of  his  variables.  When  he  uses  VARBLE  he 
means  its  value. 

The  assembly  language  programmer  will  deal  with  both  values  and 
addresses.  It  is  the  instructions  themselves  which  will  clarify  the  usage.  Some 
instructions  operate  on  values,  others  deal  with  addresses.  But  to  talk  about 
the  instructions  requires  a  new  notation.  In  this  context,  n  will  denote  an 
eight  bit  number,  and  nn  a  16  bit  number.  So  we  will  use 

nn  as  the  address,  and 
(nn)  as  the  value 

Mnemonics 

To  the  microprocessor,  an  instruction  is  a  bit  pattern  called  an  OP  code.  The 
binary  values  are  most  often  written  in  hexadecimal.  To  the  human,  a  bunch 
of  numbers,  hexadecimal  or  binary,  are  difficult  to  relate  to.  Mnemonics  are 
short,  word-like  abbreviations  for  the  instructions  which  are  translated  into 
their  numeric  equivalents  by  a  program  called  an  assembler. 

For  each  of  the  instructions  we  will  be  studying  the  hexadecimal  OP  code 
and  mnemonic  will  be  given.  Mnemonics  for  the  8080  and  Z-80  are  not  the 
same  even  though  the  OP  code  and  instruction  execution  are.  So  both 
mnemonics  will  be  given.  In  addition,  note  that  the  TDL  Z-80  assembler  uses 
8080  mnemonics. 

Eight  Bit  Load  Instructions 
Register- Register 

The  contents  of  any  eight  bit  register  can  be  moved  to  any  other  eight  bit 
register. 

MOV  E,A  (8080) 
LD  E.A  (Z-80) 

The  contents  of  register  A  would  then  be  moved  into  register  E  (to  E  from  A). 
The  target  is  listed  first.  This  class  of  load  instructions  is  denoted 


MOV  r.r'  (8080) 
LD  r.r'  (Z-80) 


18 


Z-80  and  8080  Assembly  Language  Programming 


where  r  and  r '  can  be  any  of  A,  B,  C,  D,  E,  H,  and  L,  and  the  action  is  r-«- 
r'. 

The  OP  code  for  our  sample  instruction  (E  A)  is  5Fj^.  Here  is  a  chart 
which  gives  the  OP  codes  for  all  register- register  moves. 


Register 


Source  Register 


A 

B 

C 

D 

E 

H 

L 

A 

7F 

78 

79 

7A 

7B 

7C 

7D 

B 

47 

40 

41 

42 

43 

44 

45 

C 

4F 

48 

49 

4A 

4B 

4C 

4D 

D 

57 

50 

51 

52 

53 

54 

55 

E 

5F 

58 

59 

5A 

5B 

5C 

5D 

H 

67 

60 

61 

62 

63 

64 

65 

L 

6F 

68 

69 

6A 

6B 

6C 

6D 

Register-Memory 

Eight  bit  values  can  be  loaded  from  memory  into  the  registers  and  from  the 
registers  to  memory.  Movements  between  the  accumulator  (register  A)  and 
memory  can  be  accomplished  in  several  different  ways.  Movements  between 
memory  and  any  other  register  are  very  restricted. 

We  mentioned  that  the  register  pairs  BC,  DE,  and  HL  can  be  used  as 
pointers  to  memory.  The  HL  pair  is  by  far  the  most  commonly  used  for  this 
purpose.  Suppose  we  have  the  following  situation. 


AF 

BC 

DE 

HL 

28 

7B 

04 


287A 
287B 
287C 
287D 
287E 


The  HL  register  points  to  memory  location  287B  which  contains  the  value 
04p^.  This  value  can  be  loaded  into  any  of  the  eight  bit  registers  using  the 
instruction 

MOV  r,m  (8080) 
LD  r,(HL)  (Z-80) 


I 


Where  Is  My  Variable? 


19 


In  the  8080  mnemonic,  M  indicates  a  memory  reference  and  always  refers  to 
the  memory  location  pointed  to  by  the  HL  pair. 

In  this  instruction,  the  movement  can  be  depicted  as 

r^(HL) 

Movement  in  the  opposite  direction  is  also  possible: 

(HL)^r 

Here  the  contents  of  any  eight  bit  register  can  be  stored  in  the  memory 
location  pointed  to  by  the  HL  pair.  The  instructions  are 

MOV  M,r  (8080) 
LD  (HL),r  (Z-80) 

Both  of  these  instructions  have  separate  OP  codes  for  each  eight  bit  register. 
The  OP  codes  are  summarized  in  the  following  table. 


A 

B 

C 

D 

E 

H 

L 

r  ^  (HL) 

7E 

46 

4E 

56 

5E 

66 

6E 

(HL)^  r 

77 

70 

71 

72 

73 

74 

75 

Register  A -Memory 

Additional  movements  between  the  accumulator  and  memory  are  possible. 
Four  of  them  are  just  like  the  register-memory  (HL)  instructions  just 
described.  They  are  summarized  in  the  following  table. 

Action  OP  Code  8080  Mnemonic  Z-80  Mnemonic 


A-^(BC)  0A  LDAX  B  LD  A,  (BC) 

A-^(DE)  lA  LDAX  D  LD  A,  (DE) 

(BC)-^A  02  STAX  B  LD  (BC),  A 

(DE)-^A  12  STAX  D  LD  (DE),  A 

Missing  so  far  in  all  these  register- memory  movements  is  the  ability  to 
load  the  value  of  a  variable  by  name.  That  is, 

A-»-(VARBLE) 

or 

(VARBLE)-^  A 

Both  of  these  actions  are  possible,  but  more  information  than  just  the  OP 
code  is  required.  Besides  telling  the  computer  we  want  to  load  a  variable  from 
memory,  we  have  to  tell  it  which  one. 

Before,  when  we  wanted  to  load  a  location  from  memory,  we  answered  the 
question  "Which  one?"  with  "The  one  pointed  to  by  the  HL  (or  BC,  or  DE) 


20 


Z- 80  and  8080  Assembly  Language  Programming 


pair."  So  the  location  didn't  have  to  be  contained  in  the  instruction.  This  time 
we  will  have  to  give  the  location. 

LDA  VARBLE  (8080) 
LD         A,  (VARBLE)  (Z-80) 

We  give  the  assembler  the  name  of  the  variable.  The  assembler  translates  the 
name  into  its  two  byte  address.  (It  keeps  a  symbol  table  for  this  purpose.) 

Suppose  VARBLE  is  stored  at  location  23F3.  Then  this  address  would 
become  part  of  the  instruction.  One  byte  would  be  used  for  the  OP  code  and 
two  for  the  address,  so  the  whole  instruction  would  be  three  bytes  long.  Here 
are  the  possibilities  (nn  stands  for  the  variable  name  in  the  mnemonic  and  for 
its  address  in  the  instruction). 

Operation  OP  Code  8080  Mnemonic  Z-80  Mnemonic 

A-»-(nn)  3 Ann  LDA  nn  LDA,(nn) 

(nn)— A  32nn  STA  nn  LD(nn),  A 


Register-Immediate 

Suppose  we  want  to  place  a  certain  value  into  a  register  or  memory  location. 

A—? 

The  number  7  is  an  absolute  value,  or  an  immediate.  We  can  store  any  eight 
bit  absolute  value  into  any  of  the  eight  bit  registers  or  into  the  memory 
location  pointed  to  by  the  HL  register  pair. 

The  absolute  value  desired  is  written  with  the  mnemonic  and  is 
assembled  directly  into  the  instruction.  The  instruction  then  becomes  two 
bytes  long. 

MVI  C,-27  (8080) 
LD  C,-27  (Z-80) 

After  executing  this  instruction,  register  C  would  then  contain 

(  —  27  in  2's  complement  form) 


1  1 

1 

0  0 

1 

0 

1— > 

The  possibilities  are  charted  below.  The  letter  n  stands  for  the  eight  bit 
absolute  value. 

Operation       8080  Mnemonic       Z-80  Mnemonic 


r-^n  MVI    r,n  LD  r,n 

(HL)<^n  MVI    M,n  LD  (HL),n 

The  OP  codes  for  the  immediate  instructions  are  presented  in  the  following 
table. 


Where  Is  My  Variable? 


21 


A 

B 

C 

D 

E 

H 

L 

(HL) 

3En 

06n 

0En 

16n 

lEn 

26n 

2En 

36n 

Here  s  stands  for  r  or  (HL)  and  n  is  in  2's  complement  form  if  negative. 


Z-80  Indexed  Eight  Bit  load  and  Store 

Two  other  16  bit  registers  exist  in  the  Z-80  microprocessor.  These  are  the  IX 
and  lY  index  registers. 


IX 
lY 


Like  the  stack  pointer  and  program  counter,  these  registers  are  used  exclu- 
sively to  point  to  memory  locations.  Like  the  HL  pair,  they  are  generally  used 
to  point  to  variables  in  memory. 

The  index  registers  can,  hov^ever,  be  used  with  a  displacement.  A 
displacement  is  an  eight  bit  signed  number  which  is  coded  directly  into  the 
instruction.  Here  is  an  illustration  of  how  the  index  registers  work. 


IX     3  4  4  3  n 

\  IX 

1  ir 

0  0 

\ 

I 

d:  05   

IX+d 
'-  ^ 

• 
• 
• 

F  F 

3443  (IX) 


3448  (IX+d) 


In  this  illustration  the  IX  index  register  points  to  memory  location  3443^^. 
The  value  of  the  displacement  is  05j_,.  So  the  location  that  would  be  affected 
by  the  instruction  would  be  3443^  +  05^^  =  3448^^.  Take  for  example  the 
following  load  instruction  into  the  B  register. 

MOV  B,5(X)  (TDLZ-80) 

LD  B,(IX  +  5)  (Z-80) 

At  the  conclusion  of  the  operation  register  B  would  contain  FF^^,  not  00. 

The  displacement  is  a  signed  eight  bit  number.  So  its  values  can  range 
from  -  128  to  -H  127. 

Indexed  instructions  can  be  tricky  to  deal  with,  and  much  will  be  said 
later  about  techniques  for  using  them. 


22 


Z-86and  8080  Assembly  Language  Programming 


Diagramatically,  the  load  and  store  index  instructions  fall  into  one  of 
three  categories.  Here  ii  will  mean  the  IX  or  lY  index  register.  Note  that  an 
immediate  can  be  loaded  into  an  indexed  memory  location. 

r^(ii  +  d) 
(ii  +  d)-^  r 
(ii  +  d)  n 

Since  the  displacement  is  coded  into  the  instruction,  the  instruction  must 
be  at  least  two  bytes  long.  In  fact,  it  is  three  bytes  long.  Two  bytes  are  used  for 
the  OP  code.  Most  of  the  Z-80  instructions  which  are  extensions  of  the  8080 
instruction  set  are  two  bytes  long.  All  of  the  IX  index  OP  codes  begin  with  DD 
and  the  lY  with  FD.  Index  instructions  which  include  an  immediate  are  four 
bytes  long. 

Here,  then,  are  the  OP  codes  for  the  Z-80  index  instructions. 


A 

B 

C 

D 

E 

H 

L 

r  ^  (IX+d) 

DD7Ed 

DD46d 

DD4Ed 

DD56d 

DD5Ed 

DD66d 

DD6Ed 

r  <^  (lY+d) 

FD7Ed 

FD46d 

FD4Ed 

FD56d 

FD5Ed 

FD66d 

FD6Ed 

(IX+d)^r 

DD77d 

DD70d 

DD71d 

DD72d 

DD73d 

DD74d 

DD75d 

(lY+d) 

FD77d 

FD70d 

FD71d 

FD72d 

FD73d 

FD74d 

FD75d 

(IX+d)— n  DD36dn 
(IY+d)-^n  FD36dn 


16  Bit  Load  and  Store  Instructions 
Register  Summary 

Before  going  further,  let's  take  a  moment  to  review  the  registers  discussed  so 
far: 

8080  Registers  

'  AF 

BC 
DE 
HL 
IX 
lY 
SP 
PC 


AF 

BC 

DE 

HL 

SP 

stack  pointer 

PC 

program  counter 

Register- Register 

We  saw 

that  it  was 

possible  to 

Z-80  Re 

gisters 

stack  pointer 

program  counter 

any  other  eight  bit  register.  Movements  between  16  bit  registers  are,  by 


Where  Is  My  Variable? 


23 


contrast,  almost  nonexistent.  Only  the  stack  pointer  (SP)  can  receive  a  value 
from  another  16  bit  register.  Even  then,  there  are  only  three  possibilities. 

TDLZ-80  & 

Action  OP  Code  8080  Mnemonic  Z-80  Mnemonic 


SP— HL  F9  SPHL  LDSP,HL 

SP-i-IX*  DDF9  SPIX  LDSP.IX 

SP^jY*  FDF9  SPIY  LDSP.IY 

*Z-80  only. 


Memory- Register 

In  the  eight  bit  load  instructions  it  was  possible  to  load  and  store  values  from 
memory  locations  pointed  to  by  the  HL  pair,  r-«-(HL).  This  does  not  occur 
for  16  bit  registers  at  all.  We  also  saw  that  the  contents  of  a  one  byte  variable 
could  be  loaded  into  the  accumulator  by  referencing  its  name.  A  two  byte 
variable  can  be  loaded  or  stored  in  the  HL  pair  by  referencing  its  name. 

LHLD  BIGVAR  (8080) 
LD       HL,  (BIGVAR)  (Z-80) 

Here,  the  contents  of  the  address  BIGVAR  and  the  address  BIGVAR  -I-  1  are 
loaded  into  the  HL  pair. 

Swapped  Format.  A  two  byte  variable  is  stored  in  memory  in  what  is 
known  as  swapped  format.  By  this  is  meant  that  the  low  order  byte  is  loaded 
at  the  lower  memory  address.  An  example  should  make  this  clear.  Suppose 
BIGVAR  is  stored  at  location  1F23. 


HL 


56 


43 


(after  loading 
BIGVAR) 


43 


56 


1F23  BIGVAR 
1F24  BIGVAR  +  1 


Two  byte  variables  are  not  the  only  numbers  stored  in  swapped  format.  If  an 
8080  or  Z-80  instruction  contains  within  it  a  two  byte  address,  that  address  is 
stored  in  swapped  format.  Our  example  load  instruction  has  OP  code  2A  and 
the  address  of  BIGVAR  is  contained  within  the  instruction,  so  the  instruction 
in  hexadecimal  would  be 

2A231F 

This  ability  to  load  and  store  a  named  16  bit  variable  exists  in  8080  for  the  HL 
register  pair  only.  The  Z-80  microprocessor  possesses  this  capability  for  the 


24 


Z-80and  8080  Assembly  Language  Programming 


BC,  DE,  HL,  SP,  IX,  and  lY  registers.  Here  are  the  instructions  and  OP 
codes  (nn  stands  for  the  two  byte  address,  and  rr  for  the  register  name). 

TDL  Z-80  and 

Operation        OP  Code        8080  Mnemonic        Z-80  Mnemonic 


8080  — (nn)         2Ann  LHLD  nn  LD  HL,(nn) 

&  (nn)-« — HL         22nn  SHLD  nn  LD  (nn),HL 

Z-80 


Z-80 
only 


BC  -^(nn) 

ED4Bnn 

LBCD  nn 

LD  BC,(nn) 

(nn)-*-  BC 

ED43nn 

SBCD  nn 

LD  (nn),BC 

DE  -^(nn) 

ED5Bnn 

LDED  nn 

LD  DE,(nn) 

(nn)-^  DE 

ED53nn 

SDED  nn 

LD  (nn),DE 

SP  -^(nn) 

ED7Bnn 

LSPD  nn 

LDSP,(nn) 

(nn)-^  SP 

ED73nn 

SSPD  nn 

LD  (nn),SP 

IX  ^(nn) 

DD2Ann 

LIXDnn 

LDIX,(nn) 

(nn)-^  IX 

DD22nn 

SIXDnn 

LD  (nn),IX 

lY  ^(nn) 

FD2Ann 

LIYDnn 

LD  IY,(nn) 

(nn)-^  lY 

FD22nn 

SIYD  nn 

LD  (nn),IY 

Register- Immediate 

Just  as  a  one  byte  immediate  could  be  loaded  into  any  eight  bit  register,  so  can 
a  two  byte  immediate  be  loaded  into  any  16  bit  (double  eight  bit)  register. 
Usually  that  value  is  an  address. 

LXI  H.BIGVAR  (8080) 
LD         HL.BIGVBAR  (Z-80) 

The  above  instruction  has  the  effect  of  loading  BIGVAR'S  address  (not  its 
value)  into  the  HL  pair.  Diagrammatically, 

rr^-  nn 

A  constant  can  also  be  loaded  using  these  same  instructions. 

The  8080  possesses  all  of  these  immediate  instructions  except  the  two 
that  reference  the  IX  and  lY  index  registers.  The  OP  codes  are  given  below. 


BC 

DE 

HL 

SP 

IX 

lY 

rr-*-nn 

01nn 

linn 

21nn 

3  Inn 

DD21nn 

FD21nn 

The  mnemonics  for  these  are 

LXI  rr,nn  (8080) 
LD         rr.nn  (Z-80) 

Note  that  the  meaning  of  rr  differs  for  the  8080  and  Z-80.  The  Z-80  uses 
any  one  of  BC,  DE,  HL,  SP,  IX,  or  lY.  The  8080  uses  B  for  BC,  D  for  DE,  H 


Where  Is  My  Variable? 


25 


for  HL,  and  SP  for  SP.  The  TDL  assembler  uses  the  8080  form  and,  in  ad- 
dition, X  for  IX  and  Y  for  lY. 


PUSH  and  POP  Instructions 

PUSH  and  POP  instructions  transfer  values  back  and  forth  between  register 
pairs  and  the  stack.  For  this  purpose  the  A  register  and  the  flag  register  are 
treated  as  a  pair. 

In  a  PUSH  instruction,  the  contents  of  a  registered  pair  are  stored  on  the 
stack,  and  the  stack  pointer  is  adjusted.  The  stack  always  grows  from  high  to 
low  addresses,  so  to  add  an  item  to  the  stack  the  stack  pointer  must  be 
decremented. 


SP  — 


t 

3FFD 
3FFE 
3FFF 

22 

53 

76 

• 

• 

• 

HL 


IB 


24 


The  execution  of  a  PUSH  action  has  four  distinct  phases.  Consider  the  action 
of  pushing  the  contents  of  the  HL  pair  onto  the  stack: 


1 .  The  stack  pointer  is  decremented. 


SP  — 


22 


53 


76 


3FFC 
3FFD 
3FFE 
3FFF 


HL  IB 


24 


2.  The  high  order  byte  (register  H)  is  stored. 


SP 


IB 


22 


53 


76 


3FFC 
3FFD 
3FFE 
3FFF 


HL 


IB  24 


26 


Z-8d  and  8086  Assembly  Language  Programming 


3.  The  Slack  pointer  is  decremented  again. 


SP  — 


IB 


22 


53 


76 


3FFB 
3FFC 
3FFD 
3FFE 
3FFF 


HL 


IB 


24 


4.  The  low  order  byte  (register  L)  is  stored. 


SP 


3FFB 
3FFC 
3FFD 
3FFE 
3FFF 

24 

IB 

22 

63 

76 

• 

• 

• 

The  POP  instruction  is  the  exact  opposite  of  PUSH.  For  both  the  8080 
and  Z-80  the  mnemonics  are  the  same: 


PUSH 
POP 


rr 
rr 


Again  rr  is  expressed  differently  for  the  two  mnemonic  versions,  as  was 
previously  discussed.  Also,  the  A- Flag  register  pair  is  referred  to  as  PSW 
(which  stands  for  program  status  word)  in  8080  mnemonics  and  AF  in  Z-80 
mnemonics.  Note  that  the  stack  pointer  itself  cannot  be  pushed  or  popped. 
The  relevant  OP  codes  are 


8080  &  Z-80 


Z-80  only 


AF 

BC 

DE 

HL 

IX 

lY 

PUSH 

F5 

C5 

D5 

E5 

DDE  6 

FDE5 

POP 

Fl 

CI 

Dl 

El 

DDEl 

FDEl 

Exchange  Instructions 

Elxchange  instructions  swap  register  contents,  or  contents  of  sets  of  registers. 
The  8080  instruction  set  includes  only  two  such  instructions.  The  Z-80  has  six. 
The  two  common  to  both  perform  the  followdng  actions. 


Where  Is  My  Variable? 


27 


HH  - 


DE 
(SP) 


So  the  contents  of  the  HL  register  can  be  exchanged  with  the  contents  of  the 
DE  register  or  with  the  contents  of  the  top  of  the  stack. 
HL  — —  DE 


HL- 


DE 

02 

04 

DE 

30 

07 

HL 

30 

07 

HL 

02 

04 

Before 


'(SP) 


After 


HL 

DC 

EE 

SP 

04  F0 

Before 


30 


27 


04EF 
04  F0 
04F1 
04F2 


HL 
SP 


27  30 


04F0 


After 


EE 


DC 


Mnemonics  and  OP  codes  for  these  are 

Exchange  OP  Code  8080  Mnemonic 


04EF 
04  E0 
04F1 
04F2 


Z-80  Mnemonic 


HL~-DE             EB                        XCHG  EX  DE.HL 

HL-»-^(SP)            E3                        XTHL  EX  (SP),HL 

The  Z-80  has  the  capability  to  exchange  either  the  IX  or  lY  index 
register  with  the  top  of  the  stack  as  welL 

Action              OP  Code          TDL  Z-80  Mnemonic  Z-80  Mnemonic 


(SP)— ^IX  DDES 
(SP)-— ^lY  FDE3 


XTIX 
XTIY 


EX  (SP),IX 
EX  (SP),IY 


28 


Z-80  and  8680  Assembly  Language  Programming 


The  two  other  Z-80  exchange  instructions  swap  sets  of  registers.  Besides  all  the 
Z-80  registers  given  so  far,  the  Z-80  has  a  duplicate  set  of  the  A  and  flag 
registers,  and  of  registers  BC,  DE,  and  HL.  Exchange  instructions  swap  either 
AF  and  AF'  or  BC,  DE,  HL  and  BC  ',  DE ',  HL  '.  The  swaps  appear  as 


AF 


AF' 


BC 
DE 

HL 


BC 
DE' 
HL' 


The  prime  set  cannot  be  addressed  or  acted  on  in  any  way  except  to  swap  with 
the  current  set,  which  then  becomes  dormant. 


Action 


OP  Code    TDL  Z-80  Mnemonic     Z-80  Mnemonic 


AF-«AF'  08  EXAF  EX  AF.AF' 

BCDEHL-^BCDEHL'     D9  EXX  EXX 

The  main  purpose  for  these  exchange  instructions  is  to  provide  a  very  fast 
way  of  saving  contents  of  all  the  registers.  It  is  important  to  note  that  the  only 
way  to  access  the  saved  register  is  to  swap  back.  No  values  may  be  exchanged 
directly  between  the  two  sets  of  registers. 


Exercises 

\.   Write  a  sequence  of  instructions  that  will  swap  the  contents  of  the  D  and 
E  registers. 

2.  What  will  the  B  register  contain  after  execution  of  this  instruction?  (The  -  12 
is  decimal.) 


MVI 
LD 


B,  -  12 
B,  -  12 


(8080) 
(Z-80) 


3.  Suppose  the  HL  pair  and  the  given  memory  locations  contain  the  values 
illustrated  below. 


HL 


20 


3D 


42 


F3 
39 
27 


2039 
203A 
203B 
203C 
203D 
203E 


Where  Is  My  Variable? 


29 


What  will  register  A  contain  after  the  following  sequence  of  instructions? 

8080  Z-80 


MOV  L,M  LD  L,  (HL) 

MOVA.M  LDA,(HL) 

4.  Using  swapped  format,  give  the  hexadecimal  instruction  that  loads  the  value 
of  M YVAR  (address  =  34F3)  into  the  A  register. 

5.  Give  the  effect  of 

MOV  E,12(X)  (TDLZ-80) 

LD  E,(IX+12)  (Z-80) 

6.  Explain  the  difference  between  the  following  pair  of  instructions. 

8080  Z-80 


LHLD  SPOT 
LXI  H.SPOT 
7.  Given  the  initial  register  contents 

AF:  0402 
BC:  4020 


LD  HL(SPOT) 
LD  HL.SPOT 


H 


H 


what  will  these  registers  contain  after  the  following  sequence  of  instructions? 

8080  Z-80 


PUSH  PSW 
PUSH  B 
POP  PSW 
POP  B 


PUSH  AF 
PUSH  BC 
POP  AF 
POP  BC 


8.  Would  you  expect  to  get  the  same  number  back  if  you  tried  this  sequence  of 
instructions? 

8080  Z-80 


PUSHH 
SPHL 
POP  H 

9.   Given  the  memory  locations 


PUSH  HL 
LD  SP.HL 
POP  HL 


02 


03 


04 


05 


6F32 
6F33 
6F34 
6F35 


30 


Z-80and  8680  Assembly  Language  Programming 


a.  What  instruction  will  set  the  stack  to  6F32? 

b.  What  will  register  pair  BC  and  the  stack  pointer  contain  after  execution  of 
the  following  instruction? 

POPB  (8080) 
POP  BC  (Z-80) 

What  does  the  Z-80  register  C  contain  after  execution  of  the  following  se- 
quence of  instructions? 

TDLZ-80  Z-80 


MVI  A, 3 
STA  SPOT 
LIXDSPOT 
MOV  C,-5(X) 


SPOT 


21 


22 


23 


24 


25 


26 


LD  A.  3 

LD  (SPOT),  A 

LD  IX,  (SPOT) 

LD  C,(IX-5) 


23  FE 

23FF 

2400 

2401 

2402 

2403 


a  method  to  our  logic 


In  the  first  chapter  we  discussed  the  form  used  to  store  numbers  in  the 
microprocessor,  the  method  by  which  addition  and  subtraction  are  per- 
formed, and  the  actions  of  various  logical  operators.  Now  we  must  discuss  the 
actual  instructions  which  direct  these  operations.  Like  the  load  instructions, 
we  will  have  two  main  groups:  eight  bit  and  16  bit  instructions. 

Eight  Bit  Arithmetic  and  Logical  Instructions 

The  accumulator  (register  A)  is  the  center  of  activity  for  most  of  the  eight  bit 
arithmetic  and  logical  instructions.  In  any  two-operand  instruction,  one  of 
the  operands  will  always  be  located  in  the  A  register.  The  other  operand  will 
always  be  contained  in  one  of  the  registers  listed  below. 


8080  Source  Z-80 


r  Any  eight  bit  register  r 

M  The  memory  location  pointed  (HL) 

to  by  the  HL  pair 

n  An  immediate  (eight  bit  n 

absolute  value) 

d(X)*  An  indexed  memory  location  (IX +  d) 

d(Y)*  (lY  +  d) 


•TDLZ-80. 

We  will  refer  to  any  one  of  these  collectively  with  the  letter  s. 

A^  A  +  s 

will  describe  adding  any  one  of  these  locations  to  the  accumulator.  The  8080 
version  provides  a  separate  mnemonic  for  use  when  one  of  the  operands  is  an 
immediate. 

It  will  be  extremely  important  to  consider  the  effect  on  the  flags  of  each 
of  these  operations,  since  the  flags  provide  the  programmer  with  the  means  of 
monitoring  the  run-time  execution  of  his  program.  The  flags  pertinent  to  our 
work  now  are 


31 


32 


Z-80and  8680  Assembly  Langicage  Programming 


C:  Set  on  a  carry  out  of  the  register. 

Reset  otherwise. 
Z:  Set  on  a  zero  result. 

Reset  otherwise. 
V:  Set  on  overflow  into  the  sign  bit. 

Reset  otherwise. 
S:  Set  to  a  copy  of  the  sign  bit. 
P:  Parity  flag  set  if  result  is  even,  reset  if  odd. 

Addition 

The  contents  of  the  accumulator  are  added  to  the  second  operand  and  the 
results  are  left  in  the  accumulator. 

Action"  Flags  8080  Mnemonic  Z-80  Mnemonic 

A^A  +  s         C  Z  V  S  ADDs  ADD  A.s 

ADIn 


8080  and  Z-80 

Z-80  only 

ADD 

A 

B 

C 

D 

E 

H 

L 

(HL) 

n 

(IX-i-d) 

(lY-Kd) 

OP  code 

87 

80 

81 

82 

83 

84 

85 

86 

C6n 

DD86d 

FD86d 

Addition  with  Carry 

The  contents  of  the  accumulator,  the  second  operand,  and  the  carry  flag  are 
all  added  together  and  the  result  is  left  in  the  accumulator. 

Action  Flags  8080  Mnemonic  Z-80  Mnemonic 


A-^A  +  s  +  C      C  Z  V  S  ADC  s  ADC  A,s 

ACI  n 


8080  and  Z-80 

Z-80  only 

ADD 

A 

B 

C 

D 

E 

H 

L 

(HL) 

n 

(IX+d) 

(lY+d) 

OP  code 

8F 

88 

89 

8A 

8B 

8C 

8D 

8E 

CEn 

DD8Ed 

FD8Ed 

Let's  consider  for  a  moment  the  purpose  of  an  addition  with  carry. 
Suppose  we  are  dealing  with  two  very  long  binary  numbers.  Each  is  so  long 
that  it  takes  three  bytes  to  hold  the  number:  23  magnitude  bits  and  one  sign 

Byte  3    Byte  2    Byte  1 
BIG  A  I  I  I 


BIGB 


A  Method  to  Our  Logic 


33 


The  two  numbers  can  be  added  using  the  accumulator  and  the  following 
game  plan. 

1.  Load  byte  1  of  BIGA  into  the  accumulator.  Add  byte  1  of  BIGB.  Store 
the  result. 

2.  Load  byte  2  of  BIGA  into  the  accumulator.  Perform  an  add-with-carry 
with  byte  2  of  BIGB.  Store  the  result. 

3.  Repeat  step  2  using  byte  3.  Check  for  overflow.  Store  the  result. 

We  could  ignore  the  overflow  flag  when  adding  bytes  1  and  2.  Overflow  tells 
us  the  sign  bit  is  no  longer  reliable  and  bytes  1  and  2  have  no  sign  bit. 

Subtract  and  Subtract  with  Carry 

In  a  subtract  operation  the  value  of  the  second  operand  is  subtracted  from  the 
contents  of  the  accumulator  and  the  result  is  left  in  the  accumulator. 

Action  Flags  8080  Mnemonic  Z-80  Mnemonic 

A-^A-s  C  Z  V  S  SUBs  SUB  s 

SUIn 

In  a  subtract  with  carry,  the  second  operand  and  the  carry  flag  are  subtracted 
from  the  accumulator  and  the  result  is  left  in  the  accumulator. 


Action  Flags  8080  Mnemonic  Z-80  Mnemonic 


A-^A-s-C     C  Z  V  S  SBBs  SBCA.s 

SBIn 


8080  and  Z-80 

Z-80  only 

A 

B 

C 

D 

E 

H 

L 

(HL) 

n 

(IX+d) 

(lY+d) 

Subtract 

97 

90 

91 

92 

93 

94 

95 

96 

D6n 

DD%d 

FD96d 

Subtract 
with  carry 

9F 

98 

99 

9A 

9B 

9C 

9D 

9E 

DEn 

DD9Ed 

FD9Ed 

AND,  OR,andXOR 

The  action  of  these  logical  operators  has  already  been  discussed  in  detail  in 
"Bits,  Bytes,  and  Boolean  Operators."  In  each  case  the  result  is  left  in  the 
accumulator.  The  mnemonics  and  OP  codes  are  summarized  in  the  following 
table. 


34 

Action 


Flags 


Z-80  and  8680  Assembly  Langtiage  Programming 
8080  Mnemonic  Z-80  Mnemonic 


AND  C*ZPS  ANA  s  AND  s 

ANI  n 

OR  C*ZPS  ORA  s  OR  s 

ORI  n 


XOR  C*ZPS  XRA    s  XOR  s 
  XRI  n 

*The  carry  flag  is  reset  by  all  logical  operations. 


8080  and  Z-80 

Z-80  only 

A 

B 

C 

D 

E 

H 

L 

(HL) 

n 

(IX+d) 

(lY+d) 

AND 

A7 

A0 

Al 

A2 

A3 

A4 

A5 

A6 

E6n 

DDA6d 

FDA6d 

OR 

B7 

B0 

Bl 

B2 

B3 

B4 

B5 

B6 

F6n 

DDB6D 

FDB6d 

XOR 

AF 

A8 

A9 

AA 

AB 

AC 

AD 

AE 

EEn 

DDAEd 

FDAEd 

Compare  Instruction 

The  compare  operation  is  a  subtraction  with  the  answer  thrown  away.  The 
second  operand  is  subtracted  from  the  contents  of  the  accumulator,  but  the 
accumulator  is  left  unchanged.  Only  the  flags  are  affected. 

Compare  A:  17 
s:  7 


—  s 


0  0 

0   1  0 

0 

0 

1 

0 

0 

0  0 

0 

1 

1 

1 

0 

0 

0  0 

1 

0 

1 

0 

Flag  settings: 
C:  0,  no  carry 
Z:  0,  not  a  zero  result 
V:  0,  no  overflow 
S:  0,  positive  result 


result 
discarded 


Compare  A:  7 
s:  17 


—  s 


A    0  0  0  0  0 


1 


1 


00010001 


1 


1 


0 


result 
discarded 


0 


Flag  settings: 

C:  1 ,  borrow  generated 
Z:  0,  not  a  zero  result 
V:  0,  no  overflow 
S:  1 ,  negative  result 


A  Method  to  Our  Logic 


35 


The  above  examples  illustrate  that  if  we  know  for  sure  that  the  numbers 
compared  are  both  positive  and  both  less  than  128,  then  we  know 

A  <  s  if  S  =  1  (negative  result) 
A  =  s  if  Z  =  1  (zero  result) 

A  >  s  if  S  =  0  and  Z  =  1  (positive  nonzero  result) 

Similarly,  the  flag  setting  for  ^  ,  ^  ,  and  ^  can  easily  be  determined. 

Now  suppose  we  interject  the  possibility  of  negative  numbers  in  the 
compare. 


A: 
s: 


7 
7 


result 
discarded 


A 

1 

1 

1 

1 

1 

0 

0 

1 

s 

0 

0 

0 

0 

0 

1 

1 

1 

1 

1 

1 

1 

0 

0 

1 

0 

A: 
s: 


7 
7 


Flag  settings: 

C:  0,  no  borrow  generated 
Z:  0,  not  a  zero  result 
V:  0,  no  overflow 
S:  1 ,  negative  result 


result 
discarded 


A 

0 

0 

0 

0 

0 

1 

1 

1 

s 

1 

1 

1 

1 

1 

0 

0 

1 

0 

0  0 

0 

1 

1 

1 

0 

Flag  settings: 

C:  1 ,  borrow  occurred 
Z:  0,  not  a  zero  result 
V:  0,  no  overflow 
S:  0,  positive  result 


Again  it  appears  that  the  flag  settings  discussed  for  positive  numbers  will 
work.  But  suppose  we  try  to  compare  127  and  -  127.  This  certainly  makes 
sense. 


127 


0 

1 

1 

1 

1 

1 

1 

1 

-  127 

1 

0 

0 

0 

0 

0 

0 

1 

Z: 

V: 

1 

1 

1 

1 

1 

1 

1 

0 

S: 

if  we  try  to  say  that  127  < 

-  127  because 

Flag  settings: 

1 ,  borrow  occurred 

0,  not  a  zero  result 

1 ,  overflow  occurred 
1 ,  negative  result 


negative,  we  are  obviously  talking  nonsense.  Does  this  mean  then  that  we 
cannot  compare  two  numbers  that  we  cannot  subtract?  If  so,  that  would 
impose  a  serious  restriction  on  our  ability  to  perform  comparisons. 


36 


Z-80and  8080  Assembly  Language  Programming 


A  little  analysis  reveals  the  answer.  The  overflow  flag  is  set  when  the  sign 
bit  is  clobbered.  If  the  sign  bit  has  been  clobbered,  it's  just  the  opposite  of 
what  we  want  for  our  test. 

If  V  =  0  then 

S  =  0  =#>A>  s 

S  =  1  =^  A  <  s 
If  V  =  I  then 

S  =  0  =^  S  should  really  be  1  so  A  <  s 

S  =  1  =^  S  should  really  be  0  so  A  >  s 

That's  a  lot  of  testing  and  it  looks  like  it  could  turn  into  a  lot  of  code.  Now 
suppose  we  perform  an  XOR  (exclusive  OR)  between  the  overflow  and  sign 
flags  and  compare  the  result  to  the  chart  above. 

V  S  V    XOR    S  Results  from  Chart  Above 


1 
1 
0 
0 


1 
0 
1 
0 


0 
1 
1 
0 


A  >  s 

A  <  s 

A  <  s 

A  >  s 


We  can  now  see  that 

(V  XOR  S  =  0)  =^  A>s 
(V  XOR  S  =  1)  A<s 

We  know  we  can  get  A  >  s  by  taking  A  >  s  and  weeding  out  the  case  where  A 
=  s.  So  now  we  can  relate  all  the  relationships  between  A  and  s  to  the 
corresponding  flag  settings.  Flag  settings  for  a  comparison  of  eight  bit  signed 
numbers  are: 

Relationship  Holds  if  Comment 


(:?-;) 


A<  s  VXORS  =  I 

A<  s  VXORS  =  1 

or 

Z  =  1 

A  =  s  Z  =  1 

A  +  s  Z  =  0 

A  >  s  VXORS  =  0 

and 
Z  =  0 

A  >s  VXORS  =  0 

We're  still  not  through  discussing  the  compare  operation.  What  if  the 
values  in  A  and  s  are  not  signed  numbers?  Instead  of  —  128  <  A  <  127,  we 
have  0  <  A  ^  255.  That  would  certainly  be  a  valid  interpretation  of  the  eight 


A  Method  to  Our  Logic 


37 


bits.  Such  a  representation  would  be  especially  useful  for  counting.  If,  say,  we 
wanted  to  repeat  a  certain  sequence  of  instructions  150  times,  we  may  want  to 
compare  our  current  count  to  this  limit.  How  then  shall  we  interpret  the  flag 
settings? 

Clearly  the  zero  flag  will  still  work  for  us.  But  now  the  sign  and  overflow  flags 
have  no  significance.  It  is  the  carry  flag  that  will  fill  the  gap.  The  carry  flag  is 
set  whenever  a  subtraction  generates  a  borrow  out  of  the  register. 


(C 
(C 


0) 
1) 


^  A  >  s 
^  A  <  s 


No  sign  bit  means  no  overflow  worries,  so  this  chart  is  easy.  The  flag  settings 
for  a  comparison  of  eight  bit  unsigned  numbers  are 

Relationship  Holds  if  Comment 


A<  s 
A<  s 


C  =  1 
C  =  1 

or 
Z  =  1 


A  =s 
A  =^s 
A  >  s 


A  >  s 


Z  =  1 
Z  =  0 
C  =  0 
and 
Z  =  0 
C  =  0 


/A>s\ 
I    and  I 


With  the  compare  operation  fully  analyzed,  it's  time  to  consider  the 
compare  instruction.  The  action  of  a  compare  is  described  as  (A  -  s)  since  it 
is  based  on  a  subtraction  operation.  The  fact  that  neither  operand  is  affected 
in  the  process  is  reflected  in  the  absence  of  an  arrow. 


Action 


Flags 


8080  Mnemonic 


Z-80  Mnemonic 


(A  -  s) 


cz  vs 


CMPs 
CPI  n 


CPs 


8080  and  Z=80 

Z-80  only 

A 

B 

C 

D 

E 

H 

L 

(HL) 

n 

(IX+d) 

(lY-Kl) 

Compare 

BF 

B8 

B9 

BA 

BB 

BC 

BD 

BE 

FEn 

DDBEd 

FDBEd 

Increment  and  Decrement  Instructions 

All  of  the  arithmetic  and  logical  instructions  we  have  seen  so  far  have  dealt 
with  two  operands,  at  least  one  of  which  was  in  the  accumulator.  By  contrast, 


38 


Z-80and  8086  Assembly  Language  Programming 


increment  and  decrement  instructions  have  one  operand  and  it  can  be  con- 
tained in  one  of  the  following  registers. 

8080 


Source 


Z-80 


r 

M 


d(X)* 
d(Y)* 


♦TDLZ  80 


Any  eight  bit  register 
The  memory  location 
pointed  to  by  the 
HL  pair 

An  indexed  memory 
location 


(HL) 

(IX +  d) 
(lY  +  d) 


Again,  any  one  of  these  will  be  referred  to  as  s. 

An  increment  adds  one  to  the  operand.  A  decrement  subtracts  one. 

Action  Flags  8080  Mnemonic  Z-80  Mnemonic 


s-*-s+  1 
s-^s  -  1 


Z  VS 
Z  VS 


INRs 
OCRs 


INCs 
DECs 


8080  and  Z-80 

Z-80  only 

A 

B 

C 

D 

E 

H 

L 

(HL) 

(IX-Hd) 

(lY-^d) 

Increment 

3C 

04 

0C 

14 

IC 

24 

2C 

34 

DD34d 

FD34d 

Decrement 

3D 

05 

0D 

15 

ID 

25 

2D 

35 

DD35d 

FD35d 

Operations  on  A  and  F 


Complement  Accumulator 

Complement  is  another  logical  operation.  It  differs  from  AND,  OR,  and 
XOR  in  that  it  has  only  one  operand.  The  complement  operation  is  a  I's 
complement  of  the  value,  so  every  zero  bit  is  changed  to  a  one,  and  every  one 
to  a  zero.  Often  called  a  NOT  operation,  the  complement  can  be  summarized 
in  the  following  truth  table. 


A 

NOT  A 

1 

0 

0 

1 

The  NOT  operation  is  repeated  bit  by  bit  for  every  bit  in  the  accumulator. 


A  Method  to  Our  Logic 


39 


1 

0 

1 

1 

0 

0 

0 

1 

0 

1 

0 

0 

1 

1 

1 

0 

Complementing  the  accumulator  does  not  affect  any  of  the  flags  we  have 
discussed  so  far.  The  OP  code  is  2F.  The  mnemonics  are. 

CMA  (8080) 
CPL  (Z-80) 


Negate  Accumulator 

The  Z-80  has  an  instruction  which  allows  the  accumulator  to  be  negated  (2's 
complement). 

Action  OP  Code  Flags  TDL  Z-80  and  Z-80 


A-«  A  ED  44  CZVS  NEC 

8080  programmers  can  substitute  for  NEG,  since  2's  complement  is  I's 
complement  plus  1 . 

CMA 
INR  A 


Complement  and  Set  Carry  Flag 

The  carry  flag  is  the  only  flag  which  can  be  directly  manipulated.  Choices 
include 

Action  OP  Code  8080  Mnemonic  Z-80  Mnemonic 


C    NOTC  3F  CMC  CCF 

C    1  37  STC  SCF 

Missing  is  the  ability  to  reset  the  carry.  The  easiest  way  to  reset  the  carry  is  to 
set  it  and  then  complement  it.  But  there  is  a  method  which  is  twice  as  fast. 
You  will  recall  that  any  logical  operation  (except  NOT)  clears  the  carry,  but 
the  logical  operations  affect  the  accumulator's  contents  unless  the  second 
operand  is  also  the  accumulator.  Clearly,  two  operations  exist  which  clear  the 
carry  and  leave  the  accumulator  intact.  These  are 

8080  Z-80 


ANA  A  AND  A 

ORA  A  OR  A 

Either  of  them  makes  a  fine  "clear  carry  flag"  instruction. 


40 


Z-80and  8086  Assembly  Language  Programming 


NOP  Instruction 

An  oddity  in  the  8080  and  Z-80  instruction  repertoire  is  the  NOP.  With  an 
OP  code  of  00,  the  NOP  has  the  distinction  of  being  the  instruction  that  does 
nothing.  The  abihty  to  "do  nothing"  with  a  particular  byte  of  code  can  prove 
very  valuable  at  times,  especially  during  the  debugging  process. 

16  Bit  Arithmetic  Instructions 

There  are  no  16  bit  logical  instructions,  and  only  a  limited  number  of 
arithmetic  operations  possible.  8080  programmers  are  limited  to  increment, 
decrement,  and  addition.  Increment  and  decrement  can  be  performed  on  16 
bit  registers  BC,  DE,  HL,  and  SP.  In  16  bit  addition,  register  pair  HL  acts  as 
the  accumulator.  The  other  operand  in  the  addition  operation  may  be 
registers  BC,  DE,  HL,  or  SP. 

The  Z-80  programmer  has  more  choices.  The  increment  and  decrement 
instructions  can  be  applied  also  to  the  IX  and  lY  index  registers,  and  other 
add  and  subtract  operations  are  possible.  It  is  not  possible,  however,  to  add 
the  IX  or  lY  index  register  to  the  HL  pair.  So,  before  we  discuss  the  Z-80 
extensions,  let's  summarize  the  instructions  the  two  microprocessors  have  in 
common. 

To  the  8080  programmer  rr  will  mean  any  one  of  B  for  the  BC  register 
pair,  D  for  the  DE  pair,  H  for  HL,  or  SP  for  the  stack  pointer.  TDL  Z-80  will 
also  include  X  for  the  IX  index  register  and  Y  for  the  lY  register. 
To  the  Z-80  programmer  rr  will  mean  any  one  of  BC,  DE,  HL,  SP,  IX,  or  lY, 

Action  Flags  8080  Mnemonic  Z-80  Mnemonic 


HL^HL  +  rr  C  DAD    rr  ADD  HL,rr 

rr-^rr  +  1  none  INX     rr  INC  rr 

rr<*-rr  —  1  none  DCX    rr  DEC  rr 

Note  that  since  the  overflow  and  sign  flags  are  not  set,  16  bit  operations 
must  be  handled  carefully. 


8080  and  Z-80 

Z-80  only 

BC 

DE 

HL 

SP 

IX 

lY 

ADD 

09 

19 

29 

39 

Increment 

03 

13 

23 

33 

DD23 

FD23 

Decrement 

0B 

IB 

2B 

3B 

DD2B 

FD2B 

Z-80  Extensions 

The  Z-80  instruction  set  also  includes  an  add  with  carry  and  subtract  with 
carry  that  treat  the  HL  as  an  accumulator.  Again,  the  second  operand  may 


A  Method  to  Our  Logic 


41 


be  in  registers  BC,  DE,  HL,  or  SP.  No  pure  subtract  for  16  bit  registers  exists, 
though  the  carry  may  first  be  cleared  to  achieve  the  equivalent  of  a  pure 
subtract. 

Action  Flags  TDL  Z-80  Mnemonic        Z-80  Mnemonic 

HL— HL  +  rr  +  c     CZVS  DADC  rr  ADC  HL.rr 

HL^HL  +  rr-C    CZVS  DSBC    rr  SBC  HL.rr 


Z-80  only 

BC 

DE 

HL 

SP 

Add  with 
carry 

ED4A 

ED5A 

ED6A 

ED7A 

Subtract 
with  carry 

ED42 

ED52 

ED62 

ED72 

There  are  also  Z-80  extensions  which  allow  the  IX  and  lY  registers  to  act  in 
the  role  of  accumulator. 

Action  Flags      OP  Code    TDL  Z-80  Mnemonic    Z-80  Mnemonic 


IX-^IX  +  BC 

C 

DD09 

DADX 

B 

ADD 

IX, BC 

IX— IX  +  DE 

C 

DD19 

DADX 

D 

ADD 

IX, DE 

IX— IX  +  SP 

C 

DD39 

DADX 

SP 

ADD 

IX, SP 

IX— IX  +  IX 

C 

DD29 

DADX 

X 

ADD 

IX, IX 

lY^IY  +  BC 

C 

FD09 

DADY 

B 

ADD 

IY,BC 

lY-^IY  +  DE 

C 

FD19 

DADY 

D 

ADD 

IY,DE 

lY— lY  +  SP 

C 

FD39 

DADY 

SP 

ADD 

IY,SP 

lY— IY+  lY 

C 

FD29 

DADY 

Y 

ADD 

IY,IY 

Exercises 

Write  a  sequence  of  instructions  that  will  sum  a  small  array  of  three  numbers. 
The  first  number  is  pointed  to  by  the  HL  pair,  and  the  other  two  occupy  the 
following  two  bytes  of  memory.  (You  may  assume  no  overflow  will  occur.) 


HL 


#1 

#3 


42 


Z-Sfiand  8080  Assembly  Language  Programming 


2.  Write  a  sequence  of  instructions  that  would  add  BC  and  HL,  leaving  the 
result  in  HL.  (Assume  16  bit  addition  is  not  possible.) 

3.  A  talent  agency  has  discovered  it  can  keep  all  the  information  needed  about 
the  abilities  of  its  clients  in  a  single  byte  according  to  the  following  scheme. 

Bit  7     —  1  Can  dance 
0  Can't  dance 

Bit  6    —  1  Can  sing 
0  Can't  sing 

Bit  5     —  Can  Act 

0  Can't  act 

Bit  4—1  Does  dramatic  roles 
0  Does  not 

Bit  3    —  1  Does  comic  roles 
0  Does  not 

Bit  2    —  1  Is  exceptionally  attractive 
0  Is  not 

Bit  1     —  1  Has  experience 
0  Has  none 

Bit  0    —  1  Female 
0  Male 

One  such  byte  is  in  the  accumulator.  Tell  what  instruction  will  determine  if 
the  person  involved  is  a  male,  singer-dancer,  who  can  act,  does  both  comic 
and  dramatic  roles,  is  experienced,  but  not  exceptionally  attractive.  What 
flag  will  contain  the  answer? 

4.  What  flags  will  tell  you  if  A  <  s  and  A  is 

a.  a  signed  eight  bit  number 

b.  an  unsigned  eight  bit  number 

5.  There  is  no  16  bit  compare  instruction.  Suppose  two  16  bit  signed  variables 
BIGA  and  BIGB  must  be  compared.  Describe  in  words  a  method  to  ac- 
complish this. 

6.  The  8080  programmer  has  no  16  bit  subtract.  Write  a  sequence  of  in- 
structions that  will  accomplish  the  subtraction  (if  overflow  can  be  ignored)  of 
register  pairs  BC  and  HL.  Leave  the  result  in  HL. 


jumps,  loops,  and 
modular  programming 


In  the  previous  chapter  we  spent  a  good  deal  of  time  talking  about  the  in- 
terpretation of  the  flag  settings  after  a  compare.  As  yet,  however,  we  have 
said  nothing  about  how  to  access  the  flags  and  read  their  values.  Flag  settings 
are  accessed  by  means  of  conditional  statement.  That  is,  a  command  to  do 
something  if  and  only  if  a  flag  has  a  certain  value.  The  instruction  to  be 
performed  can  be  a  jump  or  a  subroutine  call. 

Jump  Instructions 

The  normal  sequence  of  program  execution  is  to  perform  each  instruction  in 
turn  from  top  to  bottom.  The  following  pattern  is  continuously  repeated. 

1 .  Fetch  the  instruction. 

2.  Increment  the  program  counter. 

3.  Execute  the  instruction. 

A  jump  instruction  alters  the  normal  top-down  flow.  During  execution  of  the 
jump  instruction  (step  3)  the  address  in  the  program  counter  is  altered.  Now, 
when  the  next  instruction  is  fetched,  it  is  taken  from  a  different  place  in  the 
program.  So,  the  instruction  to  jump  to  location  nn  can  be  diagrammed  as 

PC-«-  nn 

The  mnemonics  and  OP  code  are 

OP  Code  8080  Mnemonic  Z-80  Mnemonic 

C3     nn  JMPnn  JP  nn 

Consider  the  following  sequence  of  instructions. 

8080  Z-80 


SUB  A  SUB  A 

LXI  H, ARRAY  LD    HL, ARRAY 

SPOT:  ADD  M  SPOT:  ADD  A,  (HL) 
INX  H  INC  HL 

JMP  SPOT  JP  SPOT 


43 


44 


Z-80and  8080  Assembly  Language  Programming 


The  accumulator  is  cleared  and  register  pair  HL  is  set  to  point  to  the  starting 
address  of  an  array  in  memory.  This  is  the  initialization  phase  of  the  loop. 
The  contents  of  the  array  location  pointed  to  by  the  HL  pair  is  added  to  the 
accumulator.  This  is  the  body  of  the  loop.  The  HL  register  pair  is  increased 
by  one.  This  is  the  increment  phase  of  the  loop.  A  jump  back  to  spot  closes  the 
loop. 

However,  something  is  dreadfully  wrong  here.  There  is  no  means  of 
terminating  the  loop.  Left  to  its  own,  it  would  go  on  forever.  When  a  con- 
dition arises  to  terminate  the  loop,  the  jump  back  should  no  longer  occur. 
Suppose  in  our  example  we  decide  that  we  should  only  repeat  the  loop  five 
times.  What  we  now  need  is  a  conditional  jump.  Here's  the  game  plan. 

1 .  Set  up  in  some  eight  bit  register  the  number  as  a  counter. 

2.  Every  time  the  loop  is  repeated,  decrement  that  register. 

3.  When  that  register  goes  to  zero,  don't  jump  back  again. 

So  what  we  need  is  an  instruction  that  performs  the  following  action. 

IfZ  =  0,  PC nn  (jump  on  nonzero) 
The  instruction  that  will  do  this  for  us  is 

OP  Code  8080  Mnemonic  Z-80  Mnemonic 


C2     nn  JNZ  nn  JP  NZ.nn 

Now  we  can  rewrite  the  sequence  of  instructions  to  add  the  first  five 
elements  in  the  array. 

8080  Z-80 


SUB  A 

LXI  H, ARRAY 
MVI  B,5 
SPOT:  ADDM 
INX  H 
DCRB 
JNZ  SPOT 


SUB  A 

LD    HL,  ARRAY 
LD  B,5 
SPOT:  ADDA,  (HL) 
INC  HL 
DEC  B 

JP  NZ.SPOT 


This  loop  can  be  broken  up  into  four  distinct  phases.  These  four  phases  will 
be  present  in  every  properly  constructed  loop: 

1.  Initialization 

2.  Body 


Jumps,  Loops,  and  Modular  Programming 


45 


3.  Increment 

4.  Test 

If  the  four  phases  appear  in  the  code  in  the  above  order,  the  loop  is  called  a 
post-test  loop.  A  pre  test  loop  will  contain  these  phases  in  the  following  order. 

1.  Initialization 

2.  Test 

3.  Body 

4.  Increment 

A  loop  of  this  form  to  perform  our  array  sum  would  be  more  difficult  to 
construct,  since  we  cannot  rely  on  our  decrement  to  set  the  zero  flag  on  the 
first  pass.  In  fact,  most  pre  test  loops  will  be  harder  to  code  in  a  lower  level 
language.  There  is,  though,  a  reason  for  their  existence.  Consider  the 
following  diagrams. 

Post-Test  Pre -Test 


Now  consider  the  shortest  route  to  Done  for  each: 

Post -Test  Pre -Test 

1.  Initialization  1.  Initialization 

2.  Body  2.  Test 

3.  Increment  3.  Done 

4.  Test 

5.  Done 


46 


Z-SOand  808d  Assembly  Language  Programming 


Notice  that  in  the  post -test  loop  the  body  of  the  loop  is  always  performed  at 
least  once.  In  the  pre  test  loop,  it  is  possible  to  avoid  performing  the  loop  at 
all.  This  then  will  be  the  criterion  for  selecting  between  the  two: 

If  there  is  ever  a  case  where  the  loop  should  not  be  performed  at  all,  use 
pretest. 


Here  is  an  example  of  a  pre  test  loop  to  add  the  first  five  elements  of  an 


array: 


8080 


SUB  A 

LXI  H, ARRAY 
MVI  B,5 

SPOT:  MOVCA 
MOV  A,B 
CMP  0 
MOV  A,C 
JZ  DONE 

ADD  M 


INX  H 
DCR  B 
JMP  SPOT 


DONE: 


Initialization 


Test 


Body 


Increment 


Z-80 
SUB  A 

LD  H, ARRAY 
LD  B,5 

SPOT:    LD  C,A 

LD  A,B 

CP  0 

LD  A,C 

JP  Z.DONE 

ADD  A,(HL) 

INC  HL 

DEC  B 

JP  SPOT 


DONE: 


Some  comments  about  the  test  phase  are  in  order.  We  first  save  the 
contents  of  the  accumulator  in  register  C.  Then  we  move  the  count  into  the 
accumulator  to  compare  it  to  0.  Now,  before  our  conditional  jump,  we 
restore  the  accumulator  to  the  sum  of  the  array.  The  move  operation  doesn't 
affect  the  flags,  so  our  jump  on  zero  is  still  valid. 

We  now  have  two  loops,  one  pre  test  and  one  post-test,  that  sum  the  first 
five  elements  of  an  array.  Both  terminate  properly,  but  are  the  results  ac- 
curate? We  have  made  no  test  to  see  if  overflow  occurred  at  any  point  in  the 
series  of  additions.  What  we  obviously  need  is  a  jump  on  overflow.  Recall, 
however,  that  the  overflow  flag  is  a  dual  purpose  flag.  It  also  serves  as  the 
parity  flag.  Thus  there  is  only  one  OP  code  for  both.  The  8080  assembler 
provides  two  different  mnemonics  for  the  same  OP  code,  the  Z-80  only  one,  so 
the  programmer  must  himself  keep  track  of  the  dual  use.  We  can  now 
summarize  the  jump  instructions. 


Jumps,  Loops,  and  Modular  Programming 

Action  OP  Code  8080  Mnemonic 


47 

Z-80  Mnemonic 


PC^nn             C3  nn  JMPnn  JP  nn 

IFZ=1,             CAnn  JZ    nn  JP  Z,nn 

PC-^nn 

IFZ  =  0,             C2  nn  JNZ  nn  JP  NZ.nn 

PC^nn 

IFC=1,             DAnn  JC    nn  JP  C,nn 

PC^nn 

IFC  =  0.             D2  nn  JNC  nn  JP  NC.nn 

PC-»-nn 

IFS=1,             FA  nn  JM    nn  JP  M.nn 

PC-^nn 

IFS  =  0,             F2  nn  JP    nn  JP  P,nn 

PC^nn 

IFP/V=1,         EA  nn  JPE  nn  JPPE.nn 

PC— nn  JO  nn 

IFP/V  =  0.         E2  nn  JPO  nn  JPPO.nn 

PC-^nn  JNO  nn 

We  could  then  make  our  loop  to  sum  the  array  more  accurate  by  inserting 
after  the  addition 

JO  OVFLOW  8080 

J  PE, OVFLOW  Z-80 

where  OVFLOW  would  be  an  address  in  our  program  that  does  something 
about  the  overflow  problem.  It  may  just  print  an  error  message  and  terminate 
the  program. 


Z-80  Relative  Jumps 

Let's  take  another  look  at  the  OP  code  of  the  jump  instruction. 

C3  nn 

We  can  see  that  it  takes  three  bytes  to  store  this  instruction.  Since  an  address 
is  two  bytes  long,  it  would  seem  to  be  impossible  to  shorten  this  instruction. 
Yet  it  can  be  done.  Remember  that  the  program  counter  points  to  the  address 


48 


Z-80and  8080  Assembly  Language  Programming 


of  the  next  instruction  to  be  executed.  Suppose  that  instruction  will  be  a 
jump.  It  is  very  likely  that  the  jump  will  be  to  an  address  near  where  we  are 
currently.  If  that  address  is  no  farther  away  than  -  128  to  +  127  bytes,  we  can 
express  that  address  as  a  distance  relative  to  the  current  location  of  the 
program  counter.  That  relative  distance  will  fit  in  one  byte. 


PC 


128 


PC  - 

(next 
instruction) 

PC 


127 


• 

• 

• 

 Range  of  a 

• 
• 

relative  jump 

• 

• 

• 

The  whole  point  of  the  relative  jump  instructions  is  this  savings  in  space. 
Take,  for  example,  our  original  program  rewritten  with  a  relative  jump. 

TDLZ-80  Z-80 


SUB    A  SUB  A 

LXI    H, ARRAY  LD    HL, ARRAY 

SPOT:  ADD  M  SPOT:  ADDA,(HL) 
INX   H  INC  HL 

JMPR  SPOT  JR  SPOT 

The  OP  code  for  the  relative  jump  instruction  is 

18e 

where  e  is  the  magnitude  of  the  relative  jump  as  a  signed  number  one  byte  in 
length. 

Ignoring  for  the  moment  the  fact  that  this  is  an  infinite  loop,  let's  hand 
assemble  these  instructions.  Assume  ARRAY  is  located  at  3F00  and  assume 
that  the  program  begins  at  2000. 


Address 


Instruction 


Action 


2000 
2001 
2004 
2005 
2006 
2008 


97 

21003F 
86 
23 
ISe 


A-^  A- A 
HL*-3F00 
A— A  +  (HL) 
PC-^PC  +  e 


Jumps,  Loops,  and  Modular  Programming 


49 


What  should  we  use  for  e?  Remember  that  the  sequence  of  program  execution 
is 

1.  Fetch  the  instruction  (get  18e). 

2.  Increment  the  program  counter  (PC  =  2008). 

3.  Execute  the  instruction. 


We  want  to  jump  to  SPOT.  SPOT  is  at  location  2004,  so  we  want  to  solve  this 
little  equation: 

2004  =  2008  -h  e 
Clearly  e  must  be  -4.  In  2's  complement: 


4 

0 

0 

0 

0 

0 

1 

0 

0 

4 

1 

1 

1 

1 

1 

1 

0 

0 

Thus,  at  location  2006  in  our  program  we  would  find 

2006:  18FC 

Fortunately,  all  this  arithmetic  is  done  for  us  by  the  assembler.  We  need  only 
use  the  relative  jump  instruction  with  the  name  of  the  location  we  want  to 
branch  to. 

Here,  then,  are  the  available  relative  jump  instructions.  Only  the  ab- 
solute relative  jump,  relative  jump  on  carry,  and  relative  jump  on  zero  are 
provided. 


Action 


OP  Code 


TDL  Z-80  Mnemonic 


Z-80  Mnemonic 


PC-^PC  +  e 


18e 


IFZ=1,  28  e 

PC-^PC  +  e 


JMPR  nn* 
JRZ  nn 


JR  nn 
JR  Z,nn 


IFZ  =  0,  20e 
PC^PC  +  e 


JRNZ  nn 


JR  NZ.nn 


IFC  =  1 
PC^PC  +  e 


38  e 


JRC  nn 


JR  C.nn 


IFC  =  0, 
PC-^PC  +  e 


30  e 


JRNC  nn 


JR  NC.nn 


•Here  the  use  of  nn  indicates  the  name  of  the  destination. 


50 


Z-8/fand  8080  Assembly  Language  Programming 


Z-80  Loop  Instruction 

There  is  another  relative  jump  instruction  available  on  the  Z-80  that  does 
more  than  just  jump  or  test  and  jump.  The  DJNZ  provides  the  capability  of  a 
built-in  loop.  Its  action  may  be  summarized  as 

B-^B  -  1 

ifB      0,  PC^PC  +  e 

The  B  register  must  first  be  set  to  the  number  of  repetitions  desired.  Choices 
range  from  1  to  256  repetitions.  By  setting  B  to  1-255,  the  corresponding 
number  of  repetitions  are  achieved.  If  B  is  initially  set  to  0,  the  first 
decrement  will  leave  B  set  to  255,  so  a  total  of  256  repetitions  will  occur  before 
B  gets  back  to  0  again. 

Let's  repeat  the  loop  that  will  sum  the  first  five  array  elements. 

TDLZ-80  Z-80 


SUB    A  SUB  A 

LXI    H, ARRAY  LD      HL. ARRAY 

MVI    B,5  LD  B,5 

SPOT:  ADD  M  SPOT:  ADD  A,(HL) 

INX    H  INC  HL 

DJNZ  SPOT  DJNZ  SPOT 

The  OP  code  for  the  decrement-jump-nonzero  instruction  10  e. 


Register  Indirect  Jumps 

The  register  indirect  jump  which  the  8080  and  Z-80  have  in  common  can  be 
diagrammed  as 

PC^HL 

That  is,  the  address  in  the  HL  register  pair  becomes  the  address  where  the 
next  instruction  will  come  from.  The  OP  code  and  mnemonics  are 

OP  Code  8080  Mnemonic  Z-80  Mnemonic 


E9  PCHL  JP  (HL) 

So  the  following  instruction  sequences  are  equivalent 

8080  Z-80 


A. 

SPOT:      ,  SPOT:  , 

JMP  SPOT  JP  SPOT 


Jumps,  Loops,  and  Modular  Programming 


51 


B. 


SPOT: 


SPOT: 


LXI  H.SPOT 
PCHL 


LD  HL.SPOT 
JP  (HL) 


At  first  sight  the  E9  one  byte  OP  code  would  seem  to  be  a  great  one  byte 
jump.  These  examples  indicate,  however,  that  its  true  cost  is  four  bytes. 
Three  bytes  are  taken  up  by  getting  the  address  into  the  HL  register. 

Needless  to  say,  this  is  not  the  most  common  form  of  a  jump.  Its  main 
value  lies  in  code  that  must  be  capable  of  running  at  any  address  whatsoever 
without  requiring  any  modification.  Such  code  is  called  self-relocating  code. 
Besides  the  use  of  the  HL  register  pair  for  this  purpose,  Z-80  programmers 
may  also  use  the  IX  or  lY  registers. 

Action  OP  Code  TDL  Z-80  Mnemonic  Z-80  Mnemonic 


Subroutines  and  Modular  Programming 

When  a  programmer  is  faced  with  any  nontrivial  task,  he  is  well  advised  to 
divide  the  task  into  individual  modules  or  subroutines.  In  this  regard  we  can 
honestly  say  that  no  programming  assignment  is  ever  difficult.  If  a  task  seems 
formidable  break  it  down  into  smaller  tasks,  each  of  which  can  be  easily 
handled. 


PC-^IX 
PC-^IY 


DDE9 
FDE9 


PCIX 
PCIY 


JP  (IX) 
JP  (lY) 


If  a  task  seems  too  big  .  .  . 


A  LESS 

Q)        FORMIDABLE  TASK 


just  break  it  up  .  .  . 


and  deal  with  the  pieces  one  by  one. 


52 


Z-80and  8080  Assembly  Language  Programming 


This  is  modular  programming  or  structured  programming.  Besides 
making  your  life  easier  when  you  code  the  program,  it  makes  the  program  far 
easier  to  understand.  Modularity  can  save  space  and  programming  effort  if 
sequences  of  instructions  that  must  be  repeated  are  written  as  subroutines 
(program  modules). 

Subroutine  calls  are  so  easy  on  the  8080  and  Z-80  that  we  can  recom- 
mend their  use  wholeheartedly  to  the  earliest  beginner  to  assembly  language 
programming.  The  basic  instruction  used  to  transfer  control  to  a  subroutine 
is 

CALLnn       8080  and  Z-80 

To  get  back,  the  basic  instruction  is 

RET       8080  and  Z-80 

We  can  diagram  the  flow  of  control  as  follows. 
MAIN 

MYSUB 


CALL  MYSUB 


RET 


A  CALL  is  like  a  jump  with  one  difference.  The  return  address  is  saved  on  the 
stack.  The  return  instruction  pops  the  stack  and  jumps  back  to  the  address 
left  there. 

That's  all  there  is  to  it.  CALL  to  get  there.  RET  to  get  back.  Everything 
needed  is  done  automatically. 

You  can  also  nest  subroutine  CALLs.  That  is,  a  subroutine  can  call  a 
subroutine  of  its  own,  and  that  subroutine  can  call  another  subroutine,  and  so 
on.  The  nature  of  the  stack  is  such  that  the  return  addresses  will  never  get 
mixed  up.  The  program  can  always  find  its  way  back. 

MAIN:  * 

CALL  SUBA 


empty  stack  SP 


SUBA:  • 


CALL  SUBB 
SUBB: 


SP 


main  s 
address 


Jumps,  Loops,  and  Modular  Programming 


53 


RET 


RET 


SP 


SUBA's 
address 


main  s 
address 


POPs  SUBA's 
return  address 
POPs  main 
return  address 


Calls  to  subroutines  and  returns  from  subroutines  can  be  made  con- 
ditional on  the  setting  of  a  flag.  The  instructions  are  nearly  identical  to  the 
conditional  jumps.  They  are 

Action  OP  Code  8080  Mnemonic  Z-80  Mnemonic 


CALL  nn 

IfZ=l, 
CALLnn 


CD  nn 


CC  nn 


CALL  nn 
CZ  nn 


CALL  nn 
CALL  Z,nn 


IfZ  =  0, 
CALLnn 


C4  nn 


CNZnn 


CALLNZ.nn 


IFC=1, 
CALL  nn 


DC  nn 


CC  nn 


CALL  C,nn 


IfC  =  0, 
CALLnn 


D4  nn 


CNC  nn 


CALLNC.nn 


IfS=l, 
CALLnn 


FC  nn 


CM  nn 


CALL  M,nn 


IFS  =  0. 
CALLnn 


F4  nn 


CP  nn 


CALL  P,nn 


IF  P/V=  1, 
CALL  nn 


EC  nn 


CPE  nn 


CALL  PE.nn 


If  P/V  =  0, 
CALL  nn 


E4  nn 


CPO  nn 
CNO  nn 


CALL  PO.nn 


54 


Z-80and  8086  Assembly  Language  Programming 


RET  C9  RET  RET 

IfZ=l,  C8  RZ  RETZ 

RET 

IfZ  =  0,  C0  RNZ  RETNZ 

RET 

IfC  =  l,  D8  RC  RETC 

RET 

IfC  =  0,  D0  RNC  RETNC 

RET 

IfS=l,  F8  RM  RETM 

RET 

IfS  =  0,  F0  RP  RETP 

RET 

IfP/V=l,         E8  RPE  RETPE 

RET  RO 

IfP/V  =  0,         E0  RPO  RETPO 

RET  RNO 

The  only  complication  possible  in  modular  programming  involves  the 
use  of  the  registers.  Most  times  both  the  main  program  and  the  subroutine 
would  like  full  use  of  the  registers.  How  can  the  subroutine  use  all  of  the 
registers  without  messing  up  their  contents  for  the  main  program?  The  answer 
is  simple.  The  subroutine  need  only  PUSH  all  of  the  register  values  onto  a 
stack,  do  its  thing,  and  then  POP  the  original  contents  back  in  before 
returning  to  the  main  program. 

Exercises 

1.  Suppose  VARA  and  VARB  are  two  unsigned,  one  byte  variables,  and  the 
following  instruction  sequence  is  executed. 

8080  Z-80 


LDA  VARA  LD   A, (VARA) 

LXI    H,VARB  LD  HL,VARB 

CMP  M  CP  (HL) 


Jumps,  Loops,  and  Modular  Programming 


55 


Write  a  sequence  of  instructions  that  will  branch  to  SPOT  if 

a.  VARA  <  VARB 

b.  VARA  <  VARB 

c.  VARA  =  VARB 

d.  VARA  VARB 

e.  VARA  >  VARB 

f.  VARA  >  VARB 

2.  Repeat  exercise  1  if  VARA  and  VARB  are  signed  numbers. 

3.  Write  a  subroutine  which  accepts  as  inputs 

a.  the  address  of  an  array  in  a  variable  named  ARYADR 

b.  the  number  of  elements  in  the  array  in  a  variable  named  SIZE 

and  produces  the  following  outputs. 

a.  The  sum  of  all  of  the  array  elements  left  in  the  accumulator,  if  no 
overflow  is  produced 

b.  if  overflow  occurs,  the  value  1  left  in  the  variable  named  OVFLAG.  The 
value  returned  in  the  accumulator  may  be  assumed  to  be  meaningless. 

No  registers  except  the  AF  pair  may  be  altered  upon  return  to  the  main 
program. 

4.  Two  16  bit  unsigned  variables  occupy  memory  locations  BIGA  and  BIGB. 
Write  a  sequence  of  instructions  that  will  call  a  routine  named  ABIGR  if 
BIGA  >  BIGB,  and  BBIGR  if  BIGA  <  BIGB. 

5.  Repeat  exercise  4  if  BIGA  and  BIGB  are  16  bit  signed  variables. 

6.  For  this  exercise  refer  to  exercise  3  in  the  section  "A  Method  To  Our  Logic." 
In  addition  to  the  assumptions  made  in  that  exercise,  assume  further  that  the 
agency  keeps  the  information  about  its  clients  in  the  following  form. 


Location 

Descriptive 

Jump 

byte 

address 

PEOPLE 

1 

1 

PEOPLE  +  3 

2 

2 

PEOPLE +  6 

3 

3 

PEOPLE  +  9 

4 

4 

• 

• 

• 

• 

• 

• 

• 

• 

• 

The  array  is  named  PEOPLE.  For  each  client  in  the  array,  there  is  a 
descriptive  byte  and  the  address  of  a  segment  of  code  that  prints  out  that 
person's  name,  address,  phone  number,  etc.  The  variable  named  COUNT 
contains  the  number  of  clients  currently  being  serviced.  Write  a  segment  of 


56 


Z- 80  and  8080  Assembly  Language  Programming 


code  that  will  look  for  the  type  of  person  described  in  the  previously  men- 
tioned exercise  3.  If  such  a  person  is  found,  control  should  pass  to  the  jump 
address  for  the  person.  If  no  such  person  is  contained  in  PEOPLE,  the  sub- 
routine named  NOSUCH  should  be  called. 


bit  fiddling  and 
message  making 


How  can  the  Z-80  programmer  manipulate  single  bits  of  data?  How  do  you 
rotate  registers  and  why  would  you  want  to?  How  are  alphabetic  characters 
stored  in  computer  memory?  How  do  you  get  data  into  and  out  of  the 
computer?  These  are  just  some  of  the  questions  that  will  be  answered  in  this 
chapter. 

Z-80  Bit  Manipulation  Instructions 

The  Z-80  has  the  capability  of  testing,  setting,  or  resetting  individual  bits 
within  a  byte.  The  bits  are  numbered  from  low  order  to  high  order. 

7   6   5   4  3   2   1  0 


The  byte  whose  bits  are  being  manipulated  may  be  located  in  any  one  of  the 
following  areas,  any  one  of  which  will  be  referred  to  as  s. 

TDL  Z-80  Location  Z-80 


r  Any  eight  bit  register  r 

M  The  memory  location  (HL) 

pointed  to  by  the 
HL  pair 

d(X)  An  indexed  memory  (IX  +  d) 

location 


d(Y)  (lY  +  d) 

The  bits  in  byte  s  will  be  referred  to  by  number.  The  letter  b  will  be  used  to 
stand  for  any  bit  number  0-7.  Thus, 

refers  to  any  bit  in  any  of  the  above  locations. 

57 


58 


Z-Sdand  838/f  Assembly  Language  Programming 


The  bit  test  instruction  sets  the  zero  flag  to  the  opposite  of  the  bit  value. 
Worded  differently,  the  bit  test  instruction  sets  the  zero  flag  if  the  bit  has  a 
zero  value  and  resets  it  otherwise.  Diagrammatically, 

 s  |b| 

The  mnemonics  for  both  TDL  Z-80  and  Z-80  are  the  same. 

BIT  b.s 

The  chart  of  OP  codes  is  large. 


Bit  Test 


Bit 

A 

B 

C 

D 

E 

H 

L 

(HL) 

(IX+d) 

(lY+d) 

0 

CB47 

CB40 

CB41 

CB42 

CB43 

CB44 

CB45 

CB46 

DDCBd46 

FDCBd46 

1 

CB4F 

CB48 

CB49 

CB4A 

CB4B 

CB4C 

CB4D 

CB4E 

DDCBd4E 

FDCBd4E 

2 

CB57 

CB5(J 

CB51 

CB52 

CB53 

CB54 

CB55 

CB56 

DDCBd56 

FDCBd56 

3 

CB5F 

CB58 

CB59 

CB5A 

CB5B 

CB5C 

CB5D 

CB5E 

DDCBd5E 

FDCBdSE 

4 

CB67 

CB6(J 

CB61 

CB62 

CB63 

CB64 

CB56 

CB66 

DIX:Bd66 

FDCBd66 

5 

CB6F 

CB68 

CB69 

CB6A 

CB6B 

CB6C 

CB6D 

CB6E 

DDCBd6E 

FDCBdGE 

6 

CB  77 

CB7(J 

CB71 

CB72 

CB73 

CB74 

CB75 

CB76 

DDCBd76 

FDCBd76 

7 

CB7F 

CB78 

CB79 

CB7A 

CB7B 

CB7C 

CB7D 

CB7E 

DDCBd7E 

FDCBd7E 

The  bit  set  instruction  sets  the  indicated  bit. 

s  jb}-l 

The  mnemonics  for  both  TDL  Z-80  and  Z-80  are  again  the  same. 

SET  b,s 
Again,  there  are  many  OP  codes  involved. 


Bit  Set 


Bit 

A 

B 

C 

D 

E 

H 

L 

(HL) 

(IX-Hd) 

(lY+d) 

CBC7 

CBCU 

CBCl 

CBC2 

CBC3 

CBC4 

CBC5 

CBC6 

DDCBdCe 

FDCBdCe 

1 

CBCF 

CBC8 

CBC9 

CBCA 

CBCB 

CBCC 

CBCD 

CBCE 

DDCBdCE 

FDCBdCE 

2 

CBD7 

CBD0 

CBDl 

CBD2 

CBD3 

CBD4 

CBD5 

CBD6 

DDCBdDG 

FDCBdD6 

3 

CBDF 

CBD8 

CBD9 

CBDA 

CBDB 

CBDC 

CBDD 

CBDE 

DDCBdDE 

FDCBdDE 

4 

CBE7 

CBE<t 

CBEl 

CBE2 

CBE3 

CBE4 

CBE5 

CBE6 

DDCBdE6 

FDCBdE6 

5 

CBEF 

CBE8 

CBE9 

CBEA 

CBEB 

CBEC 

CBED 

CBEE 

DDCBdEE 

FDCBdEE 

6 

CBF7 

CBF0 

CBFl 

CBF2 

CBF3 

CBF4 

CBF5 

CBF6 

DDCBdF6 

FDCBdF6 

7 

CBFF 

CBF8 

CBF9 

CBFA 

CBFB 

CBFC 

CBFD 

CBFE 

DDCBdFE 

FDCBdFE 

This  bit  reset  instruction  resets  the  indicated  bit. 

s  |b}^ 

Once  again  TDL  Z-80  and  Z-80  mnemonics  are  the  same. 

RES  b,s 


Bit  Fiddling  and  Message  Making 


59 


The  OP  codes  are 
Bit  Reset 


i>il 

A 
/\ 

R 

D 

c 

n 

r 

H 

X  1 

L 

1  lY+d) 

CB87 

CB8(» 

CB81 

CB82 

CB83 

CB84 

CB85 

CB86 

DDCBd86 

FDCBd86 

1 

CB8F 

CB88 

CB89 

CB8A 

CB8B 

CB8C 

CB8D 

CB8E 

DDCBdSE 

FDCBd8E 

2 

CB97 

CB90 

CB91 

CB92 

CB93 

CB94 

CB95 

CB96 

DDCBd96 

FDCBd96 

3 

CB9F 

CB98 

CB99 

CB9A 

CB9B 

CB9C 

CB9D 

CB9E 

DDCBd9E 

FDCBd9E 

4 

CBA7 

CBA(J 

CBAl 

CBA2 

CBA3 

CBA4 

CBA5 

CBA6 

DDCBdA6 

FDCBdA6 

5 

CBAF 

CBA8 

CBA9 

CBAA 

CBAB 

CBAC 

CBAD 

CBAE 

DDCBdAE 

FDCBdAE 

6 

CBB7 

CBBd 

CBBl 

CBB2 

CBB3 

CBB4 

CBB5 

CBB6 

DDCBdBo 

FDCBdB6 

7 

CBBF 

CBB8 

CBB9 

CBBA 

CBBB 

CBBC 

CBBD 

CBBE 

DDCBdBE 

FDCBdBE 

Rotate  and  Shift  Instructions 

Rotate  instructions  common  to  the  8080  and  Z-80  microprocessor  all  involve 
the  accumulator.  There  are  four  basic  types. 


Rotate  left  circular 


7^ 


•0 


□ 


Rotate  right  circular 


Rotate  left 


■0 


□ 


Rotate  right 
Action  OP  Code 


8080  Mnemonic 


Z-80  Mnemonic 


Rotate  left 
circular 


07 


RLC 


RLCA 


Rotate  right 
circular 


0F 


RRC 


RRCA 


Rotate  left 


17 


RAL 


RLA 


Rotate  right 


IF 


RAR 


RRA 


Before  we  go  into  those  rotate  and  shift  instructions  u^hich  are  exclusively  Z- 
80,  let's  spend  a  moment  discussing  why  you  might  want  to  rotate  a  register. 
Suppose  the  accumulator  has  the  following  value. 


0001    0010    =  18 


60 


Z-Sdand  8080  Assembly  Language  Programming 


Then  suppose  we  clear  the  carry  and  rotate  the  accumulator  left.  It  will  then 
contain 


0  0 

1  0  0 

1 

0  0    =  36  =  18X  2 

Suppose  instead  we  had  rotated  right.  The  accumulator  would  have  had 

0  0 

0   0  1 

0 

02j  =  9=18-2 

So  shift  and  rotate  instructions  give  us  the  capability  to  multiply  and  divide  by 
powers  of  two.  We  are  now  ready  for  a  generalized  algorithm  that  can  be  used 
for  multiplication  and  division  in  the  8080  and  Z-80. 

Multiplication  and  Division 

The  8080  and  Z-80  microprocessors  possess  no  built-in  multiply  or  divide 
instructions,  so  subroutines  must  be  written  to  provide  this  capability.  We  will 
discuss  here  algorithms  that  can  be  used  for  positive  integers. 
The  multiplication  table  for  binary  numbers  isn't  long. 

0X0  =  0 
0X1  =  0 
1X0  =  0 
1X1  =  1 

Multiplication  of  longer  numbers  is  done  in  the  same  way  as  in  the  decimal 
system. 

110  0  111 
X  10  1 

110  0  111 
0  0  0  0  0  0  0 
110  0  111 

1  0  0  0  0  0  0  0  1  1 

Notice  that  every  line  in  forming  the  product  is  either  a  copy  of  the 
multiplicand  or  all  zeroes.  The  pattern  of  shifting  each  row  one  place  to  the 
left  is  common  to  decimal  multiplication. 

Multiplication  is  notorious  for  generating  large  numbers.  Assuming  both 
multiplier  and  multiplicand  are  one  byte  signed  numbers,  how  large  can  the 
product  become?  Obviously  it's  127^  =  16,129.  We  are  way  over  one  byte  in 
length,  but  well  within  two  bytes.  In  fact,  if  we  assume  multiplier  and 
multiplicand  are  one  byte  unsigned  numbers  the  product  will  still  fit  in  a  16 
bit  unsigned  result.  The  multiply  routine  will  therefore  accept  as  inputs  two 
one  byte  signed  or  unsigned  positive  integers  and  produce  as  output  a  two 
byte  product  of  the  two. 


Bit  Fiddling  and  Message  Making 


61 


The  method  to  be  used  parallels  the  approach  used  above.  We  will  need 
three  registers  for  this  operation.  One  will  contain  the  multiplier,  one  the 
multiplicand,  and  one  we  will  clear  for  use  as  a  work  area. 


1  &  2 


00000000 


multiplier 


multiplicand 


Registers  1  and  2  will  be  used  to  contain  the  result.  Register  3  will  be  left 
unchanged. 

So  our  example  above  would  begin  as 


1  &  2 


0000000000000101 


0    110   0  1  11 


The  following  two  steps  will  then  be  repeated  eight  times. 

A.  Check  bit  0  of  register  2  (the  multiplier).  If  it  is  set,  add  the  contents  of 
register  3  (the  multiplicand)  to  register  1.  If  the  bit  is  0,  do  not  add  in 
the  multiplicand.  After  this  step  we  would  have 


1&  2 


0110011100000101 


0    110   0  111 


B.  Shift  registers  1  and  2  right  one  bit.  At  the  end  of  the  first  iteration  we 
have 


001    1001  l|l0000010| 


Continuing  this  sequence  for  our  sample  case  gives,  on  iterations  2-8, 
2. A.)  No  addition 
B.)  Shift  giving: 


0001100111000001 


3.  A.)  Add  multiplicand  +  [01100111 


100000001  1000001 


B.)  Shift  giving: 

4.  A.)  No  addition 
B.)  Shift  giving: 

5.  A.)  No  addition 
B.)jShift  giving 

6.  A.)  No  addition 
B.)  Shift  giving 


0100000001  100000 


0010000000110000 


000100000001  1000 


000010    0000001  100 


62 


Z-80and  8086  Assembly  Language  Programming 


7.  A.)  No  addition 
B.)  Shift  giving 

8.  A.)  No  addition 
B.)  Shift  giving 


00000100000001  10 


000000100000001  1 


Thus  v^e  can  see  that  the  result  agrees  with  the  long-hand  computation. 

Division  is  also  extremely  simple  when  the  dividend  and  divisor  are  in 
binary.  Consider  the  following  example. 


1000111  r  1000 


1101 


1110100011 
1101 

11000 
1101 


10111 
1101 
10101 

1101 

1000 

We  knew  that  in  multiplication  if  we  allowed  two  bytes  for  a  product  and 
restricted  inputs  to  one  byte,  we  could  never  run  into  difficulties  with  over- 
flow. Following  that  lead,  we  might  decide  to  use  a  two  byte  dividend,  a  one 
byte  divisor,  and  expect  quotient  and  remainder  to  each  remain  within  one 
byte.  But  here  we  are  not  so  lucky.  In  the  above  case  the  dividend  will  fit 
within  two  bytes,  but  if  we  divide  it  by  one  the  quotient  will  certainly  not  fit 
within  a  byte.  So  in  our  division  algorithm  we  will  have  to  be  on  the  lookout 
for  a  means  of  deducing  that  our  result  is  inaccurate.  Again,  all  inputs  will  be 
assumed  to  be  positive  integers.  We  will  again  need  three  registers.  Registers  1 
and  2  will  contain  the  two  byte  dividend.  Register  3  will  contain  the  divisor. 
Our  example  above  would  begin  as 


1&2 


0000001110100011 


0   0   0   0    1  1 


The  following  three  steps  will  be  repeated  eight  times. 
A. Registers  1  and  2  are  shifted  left  one  bit. 


0000011101000110 


B.The  contents  of  register  3  (the  divisor)  is  subtracted  from  register  1. 
1  &  2 


0000011101000110 


0   0   0   0    1    1    0  1 


1  &  2 


111110  10 


0    1    0   0   0   1    1  0 


Bit  Fiddling  and  Message  Making 


63 


C.If  the  result  of  the  subtraction  causes  a  negative  number  to  result  in 
register  1,  the  divisor  is  added  back.  If  not,  bit  0  of  register  2  is  changed 
to  A  1.  In  this  case,  a  negative  result  occurred,  so  we  add  the  divisor 
back  getting:  the  same  contents  as  after  step  A. 
Follov^ing  our  example  through  to  the  end  gives 


2.A.)  Shift  left: 

0   0  0   0   1    1    1  0 

1    0   0   0    1    1    0  0 

B.)  Subtract: 

0  0  0  0    1    1    0  1 

0   0   0   0   0   0   0  1 

1    0    0    0    1    1    0  0 

C.)  Set  bit  0: 

0   0   0   0   0   0   0  1 

1    0    0    0    1    1    0  1 

3. A.)  Shift  left: 
B.)  Subtract: 

0000001    10001  1010 

0   0   0   0    1    1    0  1 

11110  110 

0    0    0    1    1    0    1  0 

C.)  Add  back: 

0   0   0   0   0   0    1  1 

0   0   0    1    1    0    1  0 

4. A.)  Shift  left: 
B.)  Subtract: 

0   0   0   0   0    1    1  0 

0   0    110    10  0 

0   0   0   0    1    1    0  1 

111110   0  1 

0   0    110    10  0 

C.)  Add  back:  + 

0   0   0   0   0    11  0 

0    0    1    10    10  0 

5.  A.)  Shift  left: 
B.)  Subtract: 

0    0    0    0    1    1    0  0 

0    1    10    10    0  0 

0    0    0    0    1    1    0  1 

1111111101101000 

C.)  Add  back:  + 

0    0    0    0    1    1    0  0 

0    110    10    0  0 

6. A.)  Shift  left: 

0    0    0    1    1    0    0  0 

1    1    0    1    0   0   0  0 

B.)  Subtract: 

0    0    0    0    1    1    0  1 

0000101    1    1  1010000 

C.)  Set  bit  0: 

0   0   0   0    1    0    1  1 

1    1    0    1    0   0   0  1 

64 


Z-86and  8080  Assembly  Language  Programming 


7.A.)  Shift  left: 
B.)  Subtract: 


00010111  10100010 


0   0   0   0    1    1    0  1 


000010101010001 


C.)  Set  bit  0: 
8.A.)  Shift  left: 
B.)  Subtract: 


0000101010100011 


00010101010001  10 


0   0   0    1    1    0  1 


00001000010001  10 


C.)  Set  bit  0: 


00001000010001    1  1 


At  the  conclusion  of  the  division  operation  we  have 
1  &2 


Remainder 


Quotient 


A  check  of  our  original  example  shows  that  we  obtained  the  correct  answer. 

But  what  about  our  potential  overflow?  If  we  had  begun  with  the 
dividend  used  in  the  previous  example,  but  made  the  divisor  the  number  1, 
we  know  the  result  would  overflow.  But  how  would  we  know  this  happened? 

A  complicated  chain  of  reasoning  will  reveal  an  extremely  simple  test. 
We  want  to  trap  the  quotients  that  won't  fit  in  one  byte.  The  largest  signed 
number  that  will  fit  is  +  127.  So  we  want  to  know  about  it  whenever 

Dividend  > 
Divisor 


or 


or 


Dividend     >  128  x  Divisor 


Dividend     >  Divisor 
128 


So  a  first  try  might  be  to  divide  the  dividend  by  128  and  compare.  Fortunately 
128  —  2^  so  we  can  do  this  by  shifting  right  seven  bits.  Let's  try  this  on  our 
sample  case  and  see  what  we  get. 


Before: 


000000  1110100011 


After: 


00000000 


0   0   0   0   0    1    1  1 


Bit  Fiddling  and  Message  Making 


65 


We  lost  all  the  contents  of  the  high  order  byte.  This  will  always  be  true 
whenever  a  positive  number  is  input.  So  we  only  have  one  byte  left.  Compare 
it  to  the  contents  of  the  high  order  byte,  if  we  shift  one  bit  to  the  left. 


0000011101000110 


We  can  see  that  they  match.  What  has  this  gotten  us? 

In  the  first  step  of  the  division  algorithm,  we  shift  one  bit  to  the  left.  We 
have  seen  that  the  high  order  byte  then  contains 

Dividend 


128 

In  the  second  step  of  the  algorithm  we  subtract  the  divisor  from  the  high 
order  byte. 

Dividend       \  . 
  ^  Divisor 


128 

Here  is  our  compare.  It  is  done  in  the  normal  course  of  the  algorithm! 

Now  notice  that  the  third  step  of  the  algorithm  has  us  setting  bit  0  if  the 
result  of  the  subtraction  was  not  a  negative  number.  So  if  the  bit  is  set  it 
means 

Dividend  .  Dividend      ^  ^.  . 

Divisor        or    >  Divisor  0 


128  128 

This  is  exactly  the  overflow  we  were  looking  for. 

Now  a  second  try  emerges.  Simply  check  the  first  iteration.  If  the  sub- 
tract step  doesn't  produce  a  negative  result,  we're  headed  for  overflow.  Before 
we  decide  on  this  method,  though,  let's  see  what  happens  to  this  bit.  At  the 
end  of  the  first  iteration  it  is  set,  so  the  result  contains 


1  &  2 


xxxxxxxx 


xxxxxxx 1 


Seven  more  iterations  remain.  With  each  iteration  that  bit  will  be  shifted  one 
place  to  the  left.  Thus  at  the  end  of  the  algorithm  it  will  appear  as 


1  &  2 


xxxxxxxx 


Ixxxxxxx 


Right  in  the  sign  bit  itselfl 

The  final  result  of  all  this  analysis  couldn't  be  simpler: 

A  negative  result  indicates  overflow. 


We  know  that  if  dividend  and  divisor  are  both  positive  the  result  will  always 
be  positive.  So  this  gives  us  an  unfailing  check. 


66 


Z-80and  8080  Assembly  Language  Programming 


Z-80  Rotate  and  Shift  Instructions 


In  all  of  the  rotate  instructions  we  have  discussed  so  far,  the  location  of  the 
operand  was  always  the  accumulator.  The  Z-80,  however,  permits  rotation 
and  shifts  of  operands  located  in  any  of  the  following  areas 


TDL  Z-80 


Location 


M 

d(X) 
d(Y) 


Any  eight  bit  register 

The  memory  location  pointed 
to  by  the  HL  pair 

An  indexed  memory  location 


Z-80 


(HL) 

(IX +  d) 
(lY  +  d) 


Any  of  these  locations  will  be  referred  to  as  s.  The  possible  types  of  rotations 
are  the  same  as  those  for  the  accumulator. 


Action 


TDL  Z-80  Mnemonic 


Z-80  Mnemonic 


Rotate  left 
circular 


RLCR 


RLC 


Rotate  right 
circular 


RRCR  s 


RRC  s 


Rotate  left 
Rotate  right 


RALR  s 
RARR  s 


RL  s 
RR  s 


OP  codes  are  as  follows. 


A 

B 

C 

D 

E 

H 

L 

(HL) 

(IX+d) 

(lY+d) 

Rotate  left 
circular 

CB07 

CB00 

CB01 

CBd2 

CBOS 

CBd4 

cBas 

CB(»6 

DDCBd«>6 

FDCBd(j6 

Rotate  right 
circular 

CBiF 

CB08 

CB09 

CBtfA 

CB0B 

CB(JC 

CB(JD 

CB0E 

DDCBdiE 

FDCBd(JE 

Rotate  left 

CB17 

CB10 

CBll 

CB12 

CB13 

CB14 

CB15 

CB16 

DDCBdie 

FDCBdie 

Rotate  right 

CBIF 

CB18 

CB19 

CBIA 

CBIB 

CBIC 

CBID 

CBIE 

DDCBdlE 

FDCBdlE 

Besides  these  extended  rotate  instructions,  the  Z-80  possesses  the 
capability  to  perform  shifts  on  any  of  the  locations  s  described  above.  The 
possible  shift  instructions  are 


Bit  Fiddling  and  Message  Making 


67 


Shift  left  arithmetic 


•0 


0 


Shift  right  arithmetic 


-►0 


Notice  that  in  the  shift  right  arithmetic  a  zero  does  not  shift  in  on  the  left. 
Instead,  the  sign  bit  is  repeated  to  preserve  the  sign  of  the  number.  A  pair  of 
examples  should  make  this  clear.  In  each  assume  that  the  carry  flag  was 
initially  cleared. 


Effects  of  the  shift 
right  arithmetic: 


A.  Before 
After 


After 


0 

1 

0 

1 

0 

1 

0 

'! 

0 

0 

1 

0 

1 

0 

1 

1 

0 

1 

0 

1 

0 

1 

e 

1 

1 

0 

1 

0 

1 

0 

1 

0 


Shift  right  logical: 


0  *-  7 


-►0 


C 


Notice  that  no  shift  left  logical  is  needed,  since  it  would  not  be  any  different 
than  a  shift  left  arithmetic. 


The  mnemonics  are 

Action  TDL  Z-80  Mnemonic 


Z-80  Mnemonic 


Shift  left 
arithmetic 


SLAR  s 


SLA  s 


Shift  right 
arithmetic 


SRAR  s 


SRA  s 


Shift  right 
logical 


SRLR  s 


SRL  s 


The  OP  codes  are 


A 

B 

C 

D 

E 

H 

L 

(IX+d) 

(lY+d) 

Shift  left 
arithmetic 

CB27 

CB20 

CB21 

CB22 

CB23 

CB24 

CB25 

CB26 

DDCBd26 

FDCBd26 

Shift  right 
arithmetic 

CB2F 

CB28 

CB29 

CB2A 

CB2B 

CB2C 

CB2D 

CB2E 

DDCBd2E 

FDCBd2E 

Shift  right 
logical 

CB3F 

CB38 

CB39 

CB3A 

CB3B 

CB3C 

CB3D 

CB3E 

DDCBd3E 

FDCBd3E 

Two  final  rotate  instructions  available  in  the  Z-80  are  of  great  use  in 
binary  coded  decimal  (BCD)  arithmetic.  Although  this  forms  the  subject  of  a 


68 


Z-80  and  8086  Assembly  Language  Programming 


later  chapter,  the  instructions  will  be  presented  here  for  completeness.  The 
TDL  Z-80  and  Z-80  mnemonics  are  identical.  The  operands  are  always  the 
contents  of  the  accumulator  and  the  memory  location  pointed  to  by  the  HL 
pair. 


Rotate  left 
digit  (RLD) 


OP  code 
ED6F 


0 


(HL) 


I 


T 


0 


Rotate  right 

OP  code 

A 

7  4 

3 

0 

digit  i^KD) 

ED67 

i 

(HL) 

7  4 

3  0 

1 


Character  Representation  Using  the  ASCII  Code 

We  have  already  seen  that  a  byte  of  memory  may  have  many  uses.  It  can 
contain  an  instruction  OP  code  or  a  piece  of  data,  part  of  an  address  or  an 
immediate  within  an  instruction.  We  will  see  now  that  a  byte  may  also 
contain  the  coded  representation  for  a  character. 

What  if  a  programmer  wishes  to  store  customer  names  in  memory?  Since 
he  has  only  numbers  to  deal  with,  some  type  of  correspondence  between 
letters  and  numbers  must  arbitrarily  be  made.  The  ASCII  code  is  the  most 
common  code  used  in  microcomputers.  It  is  basically  a  seven  bit  code,  though 
many  systems  use  the  high  order  bit  to  signal  a  graphics  character.  A  com- 
plete chart  of  ASCII  is  included  for  reference  in  Appendix  B.  Notice  that 
there  is  a  character  1  which  in  ASCII  is  hexadecimal  31 . 

All  input  from  the  keyboard  and  output  to  screen  or  printer  is  usually 
done  in  ASCII  code.  Once  in  the  machine,  characters  can  be  stored  in  ASCII 
or  converted  to  some  other  convenient  form.  For  example,  suppose  we  read  in 
the  number  123.  In  character  form  this  is  313233^^  and  occupies  three  bytes. 
To  use  this  as  a  value  within  our  program  we  will  have  to  convert  it  to  binary. 
After  conversion  it  v^dll  fit  into  a  byte. 

Notice  that  ASCII  contains  representations  for  both  A  and  a. 

A  =  41 
a  =  61 

Many  printers  can  only  handle  upper  case.  Any  lower  case  letter  can  be 
converted  to  upper  case  by  subtracting  20^^.  This  is  often  referred  to  as 
folding  to  upper  case. 


1 


Bit  Fiddling  and  Message  Making 


69 


Whether  the  programmer  will  have  to  write  little  utility  routines  to 
convert  to  binary  and  back  again  or  to  fold  characters  to  upper  case  will 
depend  on  the  kind  of  work  he  is  doing.  Nearly  all  programs,  however, 
require  some  sort  of  1/ O  (input/output). 

A  check  of  the  instruction  repertoire  of  the  8080  will  reveal  some  nice 
input  and  output  instructions,  but  the  casual  programmer  will  never  use 
them:  The  monitor  generally  performs  all  I/O  for  the  user.  Although  this 
arrangement  is  a  tremendous  convenience  for  the  user,  it  is  a  tremendous 
headache  for  the  instructor  and  for  the  novice  programmer.  There  is  no 
standard,  set  way  of  doing  I/O.  Monitors  differ  in  both  techniques  of  use  and 
range  of  options.  The  simplest  output  technique  requires  the  user  to  place  a 
single  character  in  a  given  eight  bit  register  and  call  a  routine  that  displays  or 
prints  it.  Input  under  such  a  system  is  also  a  call  to  a  fixed  routine.  Upon 
return,  the  character  input  can  be  found  in  a  given  eight  bit  register. 

Exercises 

1 .  Write  a  subroutine  that  will  accept  as  inputs  two  eight  bit  positive  numbers 
located  in  variables  named  MLTPLR  and  MLTCND.  The  routine  should 
multiply  them  and  output  a  two  byte  result  in  a  variable  named  PRODCT. 
Save  any  registers  used  by  the  subroutine. 

2.  Repeat  exercise  1  if  MLTPLR  and  MLTCND  cannot  be  assumed  to  be 
positive.  (Hint:  Test  first.  Complement  each  if  necessary.  Complement  result 
if  necessary.  For  the  multiply  itself,  call  the  routine  in  exercise  1 .) 

3.  Write  a  routine  which  will  accept  as  inputs  a  two  byte  variable  named 
DIVDND  and  a  one  byte  variable  named  DIVSOR.  (Both  may  be  assumed  to 
be  positive.)  The  routine  should  divide  DIVDND  by  DIVSOR  and  output  the 
one  byte  quotient  and  remainder  in  variables  named  QOTENT  and 
RMANDR,  respectively.  If  an  overflow  occurs,  set  RMANDR  to  a  flag  value 
of  -  1. 

4.  For  this  exercise,  refer  to  exercise  6  in  "Jumps,  Loops,  and  Modular 
Programming."  Write  a  subroutine  that  will  sort  the  array  PEOPLE  into  two 
arrays  called  WOMEN  and  MEN.  Keep  track  of  how  many  elements  are  in 
each  array  and  store  those  values  in  suitably  named  variables. 

5.  Write  a  subroutine  that  will  accept  as  inputs  the  two  byte  address  of  an  array 
of  characters  in  a  variable  named  WHERE  and  the  number  of  characters  in  a 
variable  named  DIGITS.  All  of  the  characters  should  be  the  ASCII  code  of 
binary  digits,  i.e. , 

0  =  30H 

1  =  31h 

The  subroutine  should  convert  the  character  string  into  a  single  binary 
number  and  leave  its  value  in  a  two  byte  memory  location  named  RESULT. 


70 


Z-80and  808fi  Assembly  Language  Programming 


6 .  Repeat  exercise  5  using 

a.  all  characters  hexadecimal  digits 

b.  all  characters  decimal  digits 

(Hint:  You  may  want  to  call  the  multiply  or  divide  routines  already  written.) 

7.  Repeat  exercises  5  and  6,  going  the  other  way.  That  is,  accept  a  two  byte 
RESULT  in  binary,  output  the  characters  in  the  array,  and  store  the  number 
of  digits  required  in  DIGITS. 

8.  Learn  how  I/O  is  handled  through  the  monitor  on  your  system. 


a  casual  introduction 
to  data  structures 


Up  to  now  we  have  referred  to  variables  as  things  which  somehow  already 
were  in  existence.  We  blithely  said  things  like  "Assume  BIGA  and  BIGB  are 
16  byte  variables  in  memory."  Yet  we  have  never  hinted  at  how  they  got  there. 
By  now  we  are  used  to  writing  instructions  in  mnemonic  form  and  letting  the 
assembler  convert  them  to  OP  codes  and  addresses.  We  will  do  basically  the 
same  thing  for  variable  declaration,  but  the  mnemonics  used  to  reserve  space 
for  variables  depend  on  the  individual  assembler  you  are  using.  The  most 
common  choices  are  to 

1 .  Declare  a  one  byte  storage  area  and  assign  it  an  initial  value. 
LILVAR:  .BYTE  77 

2.  Declare  a  two  byte  storage  area  and  assign  an  initial  value. 
BIGVAR:  WORD  777 

3.  Reserve  a  stated  number  of  bytes  of  storage  with  no  initial  values 
assigned  to  them. 

ARRAY:  BLKD  7 

(In  this  example  we  get  7  bytes  of  storage  reserved.  Only  the  first  byte 
has  a  name.) 

It  would  be  a  good  idea  for  you  to  take  the  time  right  now  to  find  out  what  key 
words  your  assembler  wants  you  to  use  in  reserving  space  for  your  variables. 

Using  the  Single  Variable 

A  single  variable,  whether  one  byte  or  two  bytes  in  length,  can  be  accessed 
directly  through  its  name. 

8080  Z-80 


LDA      LILVAR  LD    A, (LILVAR) 

LHLD   BIGVAR  LD   HL. (BIGVAR) 


71 


72 


Z-Sdand  8080  Assembly  Language  Programming 


The  Array 

We  have  already  made  several  references  to  arrays,  drawing  on  previous 
experience  and  the  context  to  provide  meaning.  Basically,  whenever  there  was 
more  than  one  of  anything,  we  called  it  an  array.  To  be  more  accurate,  an 
array  is  a  collection  of  like  items.  Usually  only  the  first  element  of  the  array  is 
named.  So  our  sample  array  from  example  C  above  would  appear  as 


ARRAY 


111 


12) 


ill 


(5) 


(6) 


(Z) 


1023 
1024 
1025 
1026 
1027 

1028 
1029 


In  higher  level  languages,  we  would  typically  access  the  elements  by  sub- 
scripting. 

ARRAY(3) 

But  in  assembly  language  we  would  have  to  write 

ARRAY  +  2 

to  get  the  correct  address  in  memory.  The  trick  is  getting  used  to  counting: 


Typical  arrays  are  dealt  with  in  loops.  For  example,  we  can  add  one  to  the 
value  of  every  element  in  an  array.  If  the  individual  elements  are  single  bytes, 
this  probably  only  requires  setting  up  the  start  address  in  the  HL  pair  and 
looping  through  the  array. 


Multi-Dimensional  Arrays 

Suppose  we  wish  to  represent  in  computer  memory  an  array  that  is,  say,  4  X 
5.  It  is  convenient  for  us  to  think  of  our  storage  as  a  block 


A  Casual  Introduction  to  Data  Structures 


73 


Columns 
0  12   3  4 

Rows  0 

1 ~~~~~ 

2  

3  I  

even  though  the  bytes  are  arranged  Hnearly  in  memory,  what  must  be  done 
before  this  can  be  accompHshed  is  to  decide  on  what  order  the  elements 
should  appear  in  memory.  There  are  two  most  likely  choices. 


0 

1 

2 

3 

4 

0 

1 

2 

3 

4 

0 

0 

1 

2 

3 

4 

0 

0 

4 

8 

12 

16 

1 

5 

6 

7 

8 

9 

1 

1 

5 

9 

13 

17 

2 

10 

11 

12 

13 

14 

2 

2 

6 

10 

14 

18 

3 

15 

16 

17 

18 

19 

3 

3 

7 

11 

15 

19 

A.  Row  major  order  B.  Column  major  order 


Locating  a  specific  box  will  depend  on  the  choice  of  representation  used. 
Row  major  order 

Box  #  =  col.  #  +  (row  #)  *  (total  #  of  cols.) 
Column  major  order 

Box  #  =  row  #  +  (col.  #)  *  (total  #  of  rows) 

This  whole  concept  can  be  extended  to  three-  and  four-dimensional  arrays 
when  needed. 

The  Structure 

Closely  allied  to  the  concept  of  the  array  is  the  structure.  Where  an  array  is  a 
collection  of  like  items,  a  structure  is  a  collection  of  items  which  are  not 
necessarily  alike. 

For  example,  consider  a  collection  of  customer  entries: 

CUSTNO  NAME  ADDRSS  PHONE 


7  bytes 


20  bytes 


30  bytes 


^(—7  bytes 


^ 


74 


Z-80  and  8080  Assembly  Language  Programming 


Here  a  whole  customer  entry  is  64  bytes  long.  (This  turns  out  to  be  a  very 
convenient  size.)  So  if  we  have  a  pointer  to  the  start  of  one  entry  and  we  want 
to  get  to  the  next  we  need  only  add  64.  The  individual  fields  of  the  entries  are 
all  fixed  displacements  from  the  start  of  the  entry. 

Field  Displacement 


CUSTNO  0 

NAME  7 

ADDRSS  27 

PHONE  57 

Most  assemblers  allow  the  programmer  to  write  an  equate  statement. 
That  is,  to  create  a  word  that  can  be  used  in  place  of  a  number.  Again,  the 
key  word  to  do  this  varies  from  assembler  to  assembler. 

TWO  =  2 
or 

TWO  EQU  2 

Once  an  equate  has  been  written,  the  assembler  will  translate  all  references  to 
it  to  the  appropriate  value.  The  use  of  equates  adds  greatly  to  the  readability 
of  the  program. 

Getting  around  in  a  structure  always  involves  using  these  displacements, 
so  it  is  a  prime  candidate  for  the  indexed  instructions  which  the  Z-80  offers. 
Suppose  the  IX  index  register  points  to  one  of  the  customer  entries.  We  can 
put  the  first  letter  of  the  customer's  name  into  the  C  register  with 

TDL  Z-80  Z-80 


MOV    C,NAME(X)  LD    C,(IX  +  NAME) 

(Assuming,  of  course,  that  we  first  wrote  an  equate  statement  telling  the 
assembler  that  by  the  word  "NAME"  we  really  mean  the  number  7). 

Do  you  see  how  much  clearer  the  above  instruction  is  than  the  following? 

MOV    C,7(X)  LD    C,(IX  +  7) 

This  is  the  beauty  of  an  equate. 

8080  programmers  must  perform  an  addition  to  achieve  the  desired 
result.  Suppose  the  HL  pair  points  to  one  of  the  customer  entries.  We  can  put 
the  first  letter  of  the  customer's  name  into  the  C  register  with 

PUSH  H  Save  original  pointer 

LXI  D.NAME  Displacement  value  in  DE 

DAD  D  Add  in  displacement 

MOV  C,  M  Get  first  letter  of  name 


The  task  takes  a  little  longer  without  the  indexing  capability. 


A  Casual  Introduction  to  Data  Structures 


75 


Achieving  Variable  Displacement  in  the  Index  Instructions 

The  Z-80  index  instructions  always  involve  a  fixed,  signed  displacement  d. 
Oftentimes  a  programmer  may  desire  to  have  the  displacement  vary.  Variable 
displacement  can  be  achieved  as  follows. 

d 


IX 


Effective  address 


(IX) 


(IX+d) 


Suppose  we  wish  to  access  locations  of  varying  displacement  from  a  table 
which  begins  at  hexadecimal  location  137B.  We  know  that  the  effective 
address  of  an  index  instruction  is  the  contents  of  the  IX  index  register  plus  the 
fixed  displacement.  If,  for  example,  the  displacement  were  5 


IX 


13 


7B 


DC 


Addr.  hi^ 


Addr.  low 


+  d 


05 


+  d 


Displacement 


Effective 
address 


13 


80 


Effective  address 


Now  we  know  we  always  want  the  same  starting  location  for  the  table, 
but  we  want  to  vary  the  displacement.  So  let's  switch  things  around  a  little. 
First,  notice  that  we  get  the  same  effective  address  with 


IX 


13  05 


IX 


Addr.  high 


Displacement 


+  d 


7B 


+  d 


Addr.  low 


13  80 


Same  effective  address 


But  here  the  variable  part  is  in  the  IX  index  register  where  we  can  get  at  it  to 
change  it,  while  the  table  address  that  never  changes  anyway  is  in  the  fixed  d. 

We  will  shortly  summarize  the  program  steps  that  will  accomplish  this 
goal,  but  first  we  have  to  take  a  close  look  at  what  we  have  here.  Remember 
that  the  displacement  d  is  a  signed  number  (  -  128  <  d  <  127),  but  the  low 
order  byte  of  an  address  is  an  unsigned  number  (0  <  addr.  low  <  256).  So 
suppose  we  tried  the  same  switch  using  a  table  that  starts  at  13FF  and  a 
desired  displacement  of  5. 

13  05 


FF 


13  04 


76 


Z-80and  8080  Assembly  Language  Programming 


The  FFp^  =  —  1,  so  1305  —  1  =  1304  would  be  used  as  the  effective  address, 
though  it  is  hardly  the  desired  result. 

The  solution  centers  around  the  concept  of  boundary  alignment  and 
the  256  byte  page.  The  first  address  in  any  microcomputer  is  0000^;  the  last  is 
FFFFj^.  Memory  can  be  considered  to  be  divided  into  256  byte  pages  as 
follows. 


0000 

•         Page  0  The  start  address  of  any  page  of  memory  is  of  the 

00FF  form 


0100 

• 

• 

•  • 

Page  1 

01 FF 

0200 

• 
• 
• 

Page  2 

02FF 

XX00 

So  the  high  order  address  byte  can  be  anything,  but 
the  low  order  address  byte  is  always  00,  for  any 
address  that  is  aligpied  on  an  even  page  boundry. 


etc. 


Forcing  this  boundary  alignment  is  sometimes  essential.  The  means  by  which 
this  is  accomplished  is  the  origination  or  location  statement.  The  key  word 
used  is  again  dependent  on  the  assembler,  but  ORG  and  LOG  are  common. 

.LOG  1000H 

This  would  set  the  next  location  declared  to  hexadecimal  address  1000. 

If  we  wish  to  use  variable  displacement  to  access  an  array  named 
TABLE,  we  need  to  make  use  of  a  reference  location  we  call  TBASE,  which  is 
aligned  on  an  even  page  boundary.  TABLE  itself  may  lie  anywhere  in  the 
range  TBASE  -  128  to  TBASE  +127.  The  distance  between  TABLE  and 
TBASE  will  then  be  a  one  byte  signed  number.  We  use  this  d  as  the  fixed  dis- 
placement called  for  in  the  index  instruction.  We  use  the  high  order  byte  of 
TBASE  as  the  high  order  portion  of  the  index  register.  The  variable  displace- 
ment forms  the  low  order  portion  of  the  index  register.  This  variable  displace- 
ment will  now  be  an  unsigned  number  in  the  range  0  to  255. 


IX 


XX 


Variable  displ. 


where  -128  ^  d  <  127,  0  <  var.  displ.  <  255. 


TABLE 


TBASE 
(XX00) 


A  Castuil  Introduction  to  Data  Structures 


77 


With  the  object  clearly  in  mind,  there  remains  only  one  question.  How 
do  we  get  a  one  byte  variable  displacement  into  the  low  order  half  of  the  index 
register?  The  answer  is  that  we  plan  ahead  and  reserve  for  ourselves  a  two  byte 
area  to  which  we  have  given  the  value  XBASE  (XX00). 

INDEX:  .WORD  XBASE 


Now  the  value  of  XBASE  will  be  stored  in  memory  in  swapped  form. 


INDEX- 


XX 


Xhen  suppose  our  variable  displacement  is  contained  in  the  one  byte  memory 
location  named  DISPL.  Xhe  following  sequence  of  instructions  will  set  up  the 
IX  index  register. 


XDLZ-80 

LDA  DISPL 
SXA  INDEX 
LIXD  INDEX 


Z-80 

LD  A,  (DISPL) 
LD  (INDEX), A 
LD   IX, (INDEX) 


Linked  Structures 

All  other  data  structures  we  have  discussed  so  far  have  been  sequential  in 
nature.  Xhat  is,  the  elements  have  been  located  physically  one  after  the  other 
in  memory.  Now  we  will  briefly  introduce  a  type  of  data  structure  where  the 
elements  may  be  physically  scattered.  Xhe  individual  elements  in  such  a 
structure  are  often  called  nodes.  In  such  a  data  structure  each  element  will 
contain  the  address  where  the  next  element  can  be  found.  Xhis  is  often 
referred  to  as  the  link  field.  If  our  customer  structure  were  organized  this  way, 
it  might  look  like 


NO 

NAME 

ADDRESS 

PHONE 

LINK 

Node  1 

r  Node  2 

NO 

NAME 

ADDRESS 

PHONE 

LINK 

•  •  • 


In  this  case  it  would  no  longer  be  necessary  to  add  64  to  get  the  next  customer. 
We  need  only  load  the  value  of  the  link.  Xypically  a  link  value  like  0000  could 
be  used  to  indicate  the  end  of  the  list. 

One  obvious  advantage  of  using  a  linked  structure  comes  when  the  in- 
dividual structure  elements  must  be  arranged  in  a  certain  order.  For 


78 


Z-Sfiand  8080  Assembly  Language  Programming 


example,  suppose  our  customer  structure  is  alphabetized  by  customer  name. 
(For  convenience,  only  the  name  field  is  used.) 

Sequential  Linked 


•  •• 


Immediately  we  can  see  that  the  linked  representation  takes  more  room,  but 
not  much  more.  An  address  in  an  8080  or  Z-80  is  two  bytes  long.  So  our  link 
fields  will  add  two  bytes  to  every  node.  But  the  nodes  were  already  64  bytes 
long,  so  as  a  percentage  the  increase  is  not  great. 

Suppose,  though,  that  we  now  acquire  a  new  customer  named  AMBLE. 
Using  the  sequential  method,  we  will  have  to  move  every  entry  down  to  make 
room  for  the  new  one.  With  the  linked  representation  we  need  only  change 
ALVARADO's  link  to  point  to  AMBLE  and  have  AMBLE's  Unk  point  to 
AMBROSE. 


Available  Nodes  List 

When  linked  structures  are  used,  it  is  convenient  to  keep  a  separate  list  of 
unused  nodes. 


Empty 


•  •  • 


Then  when  a  new  entry  is  needed,  we  can  take  the  node  from  this  list. 
Similarly,  when  we  wish  to  delete  an  existing  node  from  the  linked  structure, 
we  can  return  it  to  this  list  to  be  reused  at  a  later  time. 


A  Casual  Introduction  to  Data  Structures 


79 


Z-80  Block  Handling  Instructions 

The  Z-80  instruction  set  contains  eight  operations  that  act  on  blocks  of  data. 
Whole  arrays  can  be  moved  or  searched  using  a  single  command.  We  will 
outline  the  effects  of  the  instructions  and  then  discuss  how  these  instructions 
might  influence  the  way  we  chose  to  store  arrays  using  the  Z-80. 

Z-80  Block  Transfer  Group 

The  Z-80  Block  transfer  instructions  make  use  of  three  register  pairs: 

BC:  Holds  the  count  telling  how  many  bytes  are  to  be  moved. 

DE:  Points  to  the  destination  location  to  which  the  next  byte  will  be 

moved. 

HL:  Points  to  the  source  location  from  which  the  next  byte  will  be  fetched. 

The  load  and  increment  instruction  LDI  moves  one  byte  from  (DE)  to 
(HL)  and  then  increments  both  DE  and  HL  and  decrements  register  pair  BC. 
The  dual  purpose  flag  parity/overflow  is  set  if  BC  /=  0  and  it  is  cleared  if  BC 
=  0.  The  carry  flag  is  unaffected,  but  the  zero  and  sign  flags  are  messed  up. 
The  OP  code  for  this  instruction  is  EDA0. 

The  load,  increment,  and  repeat  instruction  LDIR  performs  the  same 
action  as  the  LDL  but  continues  transferring  bytes  one  by  one  until  the  count 
in  the  BC  register  pair  reaches  zero.  It's  OP  code  is  EDB0. 

The  load  and  decrement  instruction  LDD  moves  one  byte  from  (DE)  to 
(HL)  and  then  decrements  all  three  register  pairs.  Flag  settings  are  the  same 
as  for  the  LDL  The  OP  code  is  EDA8. 

The  load,  decrement,  and  repeat  instruction  LDDR  performs  the  LDD 
until  the  BC  pair  goes  to  0.  Its  OP  code  is  EDB8. 

Z-80  Block  Search  Group 

The  Z-80  block  search  instructions  make  use  of  two  register  pairs  and  the 
accumulator. 

A:  Holds  the  value  to  be  searched  for. 
BC:  Holds  the  count  telling  how  many  bytes  are  to  be  searched. 
HL:  Points  to  the  location  of  the  next  byte  to  be  searched. 

The  flag  settings  for  these  instructions  are  all  the  same. 
CARRY:  Unaffected. 

ZERO:  Set  if  A  =  (HL).  Cleared  if  A  (HL). 

PARITY/ 

OVERFLOW:    Setif  BC  ^  0.  Cleared  if  BC  =  0. 
SIGN:  Messed  up. 


80 


Z-86  and  8080  Assembly  Language  Programming 


The  compare  and  increment  instruction  CPI  performs  a  compare 
[A  — (HL)];  then  increments  the  HL  pair  and  decrements  the  BC  pair.  The 
OP  code  is  EDM. 

The  compare,  increment,  and  repeat  instruction  CPIR  performs  the 
action  of  the  CPI  instruction  until  either  BC  9^  0,  or  A  =  (HL).  Its  OP  code  is 
EDBl. 

The  compare  and  decrement  instruction  CPD  performs  a  compare 
[A  — (HL)],  then  decrements  both  the  HL  and  BC  register  pairs.  The  OP  code 
is  EDA9. 

The  compare,  decrement,  and  repeat  instruction  CPDR  performs  the 
action  of  the  CPD  instruction  until  either  BC  =  0  or  A  =  (HL).  Its  OP  code 
is  EDB9. 


Z-80  Array  Arrangement 


Suppose  we  are  writing  a  program  that  requires  a  large  array  of  two  byte 
signed  variables  which  are  not  sorted  in  any  particular  order. 


HI  GARY 


IL 

IH 

2L 

2H 

3L 

3H 

2002 
2004 
2006 


Further,  suppose  that  we  frequently  have  to  determine  whether  or  not  a 
certain  two  byte  variable,  called  TSTVAL,  is  contained  within  BIGARY.  If 
all  of  these  variables  were  one  byte  in  length,  there  would  be  no  problem.  We 
would  simply  use  the  search  instruction.  However,  there  is  no  two  byte  search. 
We  can  still  use  the  built-in  search,  though,  if  we  split  up  the  array  into  two 
arrays  of  one  byte  variables. 


Low  order 


High  order 


ARYLO 


IL 


2L 


3L 


ARYHI 


 ► 

IH 

2H 

3H 

• 

• 

• 

We  would  also  conceptually  divide  TSTVAL  into  a  high  and  low  order  byte. 
Now  we  can  search  just  the  low  order  byte  for  a  match  with  TSTVAL/low.  If 
we  find  one,  we  check  the  corresponding  high  order  byte  for  a  match  with 
TSTVAL/high.  If  they  match,  we're  done,  if  not,  we  just  go  on  checking  the 
low  order  byte  array. 


A  Casual  Introduction  to  Data  Structures 


81 


Many  times  it  will  turn  out  to  be  simpler  to  split  the  fields  of  a  structure 
in  this  manner  as  well.  In  our  customer  structure,  for  example,  it  may  be 
more  convenient  to  keep  several  parallel  arrays. 


CUSTNO 


NAME 


Exercises 

When  an  array  contains  a  string  of  characters  that  is  being  input  or  output  a 
character  at  a  time,  it  is  usually  called  a  buffer.  Using  the  keywords  that  your 
assembler  requires  to  reserve  storage,  define  a  buffer  large  enough  to  hold  30 
characters.  Write  a  subroutine  that  will  accept  a  string  of  characters  from  the 
keyboard  and  place  them  in  successive  buffer  locations.  The  input  should  be 
terminated  by  a  carriage  return,  but  do  not  include  that  character  in  the 
buffer.  Clear  any  unused  buffer  locations  by  inserting  the  ASCII  character  for 
a  space.  Do  not  allow  the  buffer  to  overflow.  Each  character  input  should  be 
echoed  on  the  screen  or  printer. 

Write  a  subroutine  which  will  display  a  message  on  the  screen  or  printer.  The 
routine  should  be  passed  a  starting  location  of  the  message  and  the  number  of 
characters. 

Write  a  driver  routine  that  calls  the  subroutines  written  in  exercises  1  and  2 
above.  It  should  display  the  following  three  questions  in  turn,  and  accept  a 
response  for  each. 

NAME? 
ADDRESS? 
PHONE  NUMBER? 

The  driver  should  have  storage  areas  reserved  for  the  answers  and  should 
transfer  the  information  from  the  buffer  after  each  question.  The  area 
reserved  for  phone  number  should  be  eight  characters  long.  Name  and 
address  may  be  any  suitable  length  up  to  30  characters. 

When  using  a  linked  structure,  the  available  nodes  list  keeps  the  track  of 
unused  nodes.  Suppose  we  have  a  linked  structure  where  the  nodes  are  64 
bytes  long,  and  where  the  first  two  bytes  contain  the  link  field. 


82 


Z-80and  8080  Assembly  Language  Programming 


Reserve  an  area  of  storage  which  is  Ik  (400^)  in  length.  Force  boundary  align- 
ment so  that  it  begins  on  an  even  page  boundary. 

a.  Write  a  subroutine  that  will  link  up  all  of  the  storage  space  into  one  big 
available  nodes  list.  Leave  a  pointer  to  the  first  node  in  a  two  byte 
variable  named  AVAIL.  The  last  node  should  have  a  zero  link  value. 

b.  Write  a  subroutine  that  will  get  a  node  off  from  the  available  list  and 
return  a  pointer  to  it  in  the  HL  pair. 


Before  After 


AVAIL 


Your  routine  should  check  to  see  if  the  available  nodes  list  is  empty  and 
should  call  a  routine  called  OVFLOW  if  it  is. 

c.  Write  a  subroutine  that  will  accept  a  pointer  to  a  node  in  the  HL  pair 

and  return  that  node  to  the  available  nodes  list.  That  is,  reverse 

"before"  and  "after"  pictures  of  part  b. 


binary  coded 
decimal  arithmetic 


From  previous  exercises,  vs^e  have  gained  experience  v^riting  conversion 
subroutines  that  accept  as  input  ASCII  characters  of  digits  and  produce  as 
output  the  binary  equivalent  of  the  number.  For  example,  an  input  in 
characters  of  1 1  would  be  converted  to  a  binary  1011,  since 

Then,  if  we  were  to  store  that  number  in  an  eight  bit  register,  it  would  appear 
as 


0   0   0   0    1    0    1  1 


If  we  were  to  store  the  decimal  number  11  in  binary  coded  decimal,  however, 
it  would  appear  in  a  register  as 


0   0   0    1    0   0   0  1 


In  binary  coded  decimal  arithmetic,  each  decimal  digit  is  translated  into 
binary  and  stored  in  half  a  byte  (one  nibble).  So  only  the  following  binary 
values  are  used. 


0000  =  0 

0001  =  1 

0010  =  2 

0011  =  3 

0100  =  4 

0101  =  5 

0110  =  6 

0111  =  7 

1000  =  8 

1001  =  9 


83 


84 


Z-80and  8080  Assembly  Language  Programming 


The  binary  numbers  below  are  not  used. 


1010  =  A 

1011  =  B 

1100  =  C 

1101  =  D 

1110  =  E 

1111  =  F 

So  if  we  now  consider  the  largest  number  that  will  fit  in  the  accumulator,  we 
see  that  it  is 


1    0  0    1    1    0   0  1 


=  99 

BCD  ^^D 


Now  99  isn't  a  very  large  number,  especially  in  light  of  financial  applications 
which  use  an  implied  decimal  point.  If  dollars  and  cents  are  the  units,  our  99 
becomes  99<f .  —  this  is  terribly  limiting.  Nor  does  use  of  a  16  bit  register  help 
much  — with  it  we  can  only  go  up  to  $99.99. 

The  desired  size  range  for  BCD  numbers  can  only  be  achieved  by  storing 
the  numbers  in  memory  and  manipulating  them  in  memory  as  well.  Thus,  a 
BCD  number  will  appear  as  an  array  of  bytes  in  memory,  each  byte  con- 
taining two  digits. 


1,256,743.27  = 


01 


25 


67 


43 


27 


Notice  that  only  the  digits  themselves  appear  in  memory,  not  the  decimal 
point.  The  fact  that  two  digits  follow  the  decimal  point  will  be  contained  in  a 
descriptor  block  which  will  also  give  the  size  of  the  number  in  bytes  and  the 
sign  of  the  number,  whether  positive  or  negative. 


Decimal  Adjust  Instruction 

Suppose  we  decided  to  add  two  BCD  numbers.  For  convenience,  let's  suppose 
each  number  is  exactly  two  digits  long. 

19 

+  23 
42 

Now  let's  see  what  we  would  get  in  the  accumulator  if  we  performed  addition 
on  these  two  numbers  in  BCD. 


Binary  Coded  Decimal  Arithmetic 


85 


0   0   0    110    0  1 


+    0    0    1    0   0   0    1  1 


0   0  11 


110  0 


=  3C 


Whoops!  The  result  of  this  addition  left  us  with  one  of  the  unused  binary 
numbers,  namely  C  =  1100.  So  we  added  two  BCD  numbers,  but  the  result 
was  not  a  BCD  number. 

We  would  have  a  similar  problem  upon  performing  the  following 
subtraction: 

57 
-  19 
38 


0    10    10  111 


1110   0  110 


0   0  111110 


3E 


So  how  can  we  add  or  subtract  BCD  numbers?  The  answer  comes  in  the  form 
of  an  additional  instruction.  The  decimal  adjust  instruction  DAA,  OP  code 
27,  takes  a  result  in  the  accumulator,  such  as  the  3C  from  the  above  addition, 
and  automatically  corrects  it  to  the  value  42.  The  same  instruction  also 
corrects  the  outcome  of  a  subtraction  operation. 

Multi-byte  addition  and  subtraction  algorithms  will  be  given  later.  Now 
that  we  know  we  can  successfully  add  and  subtract  BCD  numbers,  let  us  turn 
our  attention  to  conversions  between  character  and  BCD  forms  of  the 
numbers. 


Input  and  Output  of  BCD  Numbers 

We  know  that  BCD  numbers  will  be  stored  in  memory  with  two  digits  per 
byte,  but  the  same  numbers  will  be  input  and  output  in  character  form.  For 
example,  if  the  number  1234  were  input  from  the  keyboard  it  would  appear 
in  the  input  buffer  in  character  form.  Then  it  would  have  to  be  "packed"  into 
BCD  form  as  illustrated  below. 


31 

32 

33 

34 

12 


34 


Similarly,  on  output,  conversion  would  have  to  go  the  other  way. 


.56      78  . 


35 


36 


37 


38 


86 


Z-80and  8086  Assembly  Language  Programming 


Let's  consider  how  this  conversion  might  be  done.  From  character  to 


BCD 


1 .  Load  the  first  digit  into  the  accumulator.  A|  0  0   1    l|0  0  0  1 

A 


=  31 


H 


2.  Subtract  30^. 


3.  Rotate  the  accumulator  four  times  to 
the  left. 


00000001=  01 


0   0   0    1    0   0   0  0 


=  10 


H 


4.  Save  this  value  in  a  temporary  storage  B00010000 
location. 


5.  Load  the  second  digit  into  the 
accumulator. 

6.  Subtract  30, 


'H' 


A 
A 


0  0   1    1 1  0  0   1   0| =  32h 

02 


0    0   0    0   0    1  0 


H 


0    0    0    010    0    1  0 


7.  Add  in  the  value  from  the  temporary 
storage  location. 

8 .  Save  the  result  as  the  first  byte  of  the     +B  |  0  0  0   f  0  0  0  0 
BCD  number. 


02 


H 


=  10 


H 


0   0   0    1    0    0    1    01  =  12h 


The  above  steps  would  be  repeated  for  each  pair  of  characters  input. 
Converting  from  BCD  to  character 

1 .  Load  the  first  byte  of  the  BCD 
number  into  the  accumulator. 

2.  Perform  an  "AND"  operation  with 


0   1   0   1   0   1    1   0    =  56 


H 


a  mask  whose  value  is  F0 


H- 


A 

AND  mask 


1   0   1   0   1    1   0  =  56 


H 


1111 


0   0   0   0    =  F0 


'H 


0    1    0    1    0   0    0  0 


=  50 


H 


3.  Rotate  the  accumulator  to  the 
right  four  times. 


0    0   0   0   0    1    0  1 


=  05 


H 


4.  Add  in  30 


H 


0   0    110  101 


=  35 


H 


5.  Output  the  result  as  the  first 
digit  in  character  form. 

6.  Load  the  first  byte  of  the  BCD 
number  into  the  accumulator  again. 

7.  Perform  an  "AND"  operation 


0    10    10  110 


=  56 


H 


A  0   1   0   1   0   1    1  0 


=  56 


H 


with  a  mask  whose  value  is  0Fj^. 


AND  mask  0  0  0  0 


1111 


=  0F 


H 


0   0    0    0   0    1    1  0 


=  06 


H 


8.  Add  30 and  output  the  result 

as  the  second  character  of  the  result. 


0   0    110  110 


=  36 


H 


Binary  Coded  Decimal  Arithmetic 


87 


Again,  all  eight  steps  would  have  to  be  repeated  for  each  pair  of  characters 
output. 


RLD  and  RRD  in  Character-BCD  Conversions 

The  8080  programmer  has  no  choice  but  to  use  the  above  algorithm  or  one 
equivalent  to  it.  The  Z-80  programmer  can  make  use  of  the  RLD  and  RRD 
instructions  to  simplify  the  conversion  routines.  These  two  instructions  have 
been  discussed  before,  but  they  are  diagrammed  again  here  for  reference. 


(HL) 


1            A  1 

1  

1 
« 

+  1 

"■  1 

i  i 

f--  i 

'  r-' 

(HL) 

1 

L  i 

RLD 


RRD 


Let's  trace  how  the  algorithms  would  go  using  these  instructions  for 
conversion  from  character  to  BCD.  Assume  the  following  register  pairs  are 
used  as  pointers. 

HL:  points  to  the  first  character  in  the  input  buffer 
DE:  points  to  the  first  byte  of  the  BCD 

1 .   Clear  the  accumulator  and  RRD  the  first  digit  into  the  accumulator. 

00.,  A  1000  0|  000   l|=  01 


00000000 


H 


H 


(HL)  1 0   0    1    1  I  0   0   0  31h       (HL)  I  0   0   0   0|  0   0    1    l|  =  03^ 

Before  After 

2.  Store  the  contents  of  the  accumulator  into  the  location  pointed  to  by  the 
DE  pair. 

3.  Increment  the  HL  pair  to  point  to  the  next  character,  and  repeat  step  1 . 


0  0   0   0   0   0    1  0 


4.  Now  exchange  the  contents  of  the  DE  and  HL  registers  (DE-^ — ^  HL) 
so  the  HL  pair  points  to  the  first  byte  of  the  BCD  number.  Then  RLD 
second  digit  into  the  byte. 

'  '  '  =  00 


0   0   0   0   0   0    1  0 


=  02 


H 


00000000 


H 


(HL)  |0   0   0   0|0   0   0    1  I  =  OIh     (HL)  |0   0   0    1  I  0   0    1    0|  =  12^ 

Before  After 
These  four  steps  can  then  be  repeated  for  each  pair  of  digits  input. 


88 


Z-80  and  8080  Assembly  Language  Programming 


Storing  the  BCD  Number  in  Memory 

We  have  aheady  stated  that  a  BCD  number  generally  occupies  several  bytes 
and  requires  some  type  of  descriptor  block  telling 

1 .  size 

2 .  number  of  digits  to  the  right  of  the  decimal  point 

3.  sign 

The  method  presented  below  is  by  no  means  the  only  possible  way  to  store  this 
information.  Its  main  advantage  is  simplicity.  The  maximum  size  of  the 
number  to  be  dealt  with  is  completely  up  to  the  programmer  and  will  depend 
on  the  application.  The  storage  area  to  be  reserved,  however,  will  be  three 
bytes  larger  than  the  space  required  to  hold  the  longest  possible  number. 
Those  thcee  bytes  will  then  hold  the  descriptor  data  for  the  number. 

1234.56 


would  appear  in  memory  as 


06 


02 


12 


34 
56 


The  number  is  6  digits  long, 

two  digits  to  the  right  of  the  decimal  point,  and 

the  number  is  positive  (01^  indicates  negative). 

This  is  the  number  itself. 


Alignment  of  the  BCD  Number 

We  have  still  not  completely  characterized  the  BCD  number.  Suppose  the 
following  number  is  input. 

123.45 

This  number  has  five  digits  in  it,  and  we  pack  two  to  a  byte,  so  there  will  be  an 
odd  digit  left  over.  Should  we  store  the  number  as 


_01_ 

23 
45 


or 


12 
34 
50 


The  first  method  will  turn  out  to  be  the  simplest  to  deal  with,  because  in  this 
representation  the  decimal  point  lies  between  two  bytes  and  not  in  the  middle 
of  a  byte.  This  will  turn  out  to  be  extremely  useful  in  addition  and  subtraction 


Binary  Coded  Decimal  Arithmetic 


89 


of  numbers  with  decimal  points  in  different  places.  In  fact,  we  will  make  it  a 
rule  always  to  have  the  decimal  point  on  a  byte  boundary. 

123.456 

would  appear  in  memory  as 


01 

23 
45 
60 


But  now  what  should  we  put  in  the  descriptor  block?  We  have  just 
changed  both  the  number  of  digits  in  the  number  and  the  number  to  the  right 
of  the  decimal  point.  The  answer  is  that  we  will  want  to  use  the  descriptor 
block  to  tell  us  the  total  number  of  bytes  to  the  right  of  the  decimal  point. 


Number  of  bytes 

in  number  

Number  of  bytes 
to  the  right 
of  the  decimal 
point 

Sign  

Value 


Now  what  about  our  input  routines?  We  designed  them  as  though  the 
number  would  simply  be  read  from  left  to  right  in  the  buffer.  Now  we  want  to 
work  outward  from  the  decimal  point  in  both  directions.  Does  this  mean  the 
whole  set  of  routines  will  have  to  be  discarded?  Fortunately,  this  will  not  be 
necessary  if  we  are  careful  in  the  design  of  our  data  areas.  The  algorithm  to 
be  used  will  be  outlined,  but  at  this  time  let  us  also  discuss  how  to  set  up  the 
descriptive  block  and  how  to  deal  with  extraneous  character  inputs  such  as  "," 
or  .  or    +  . 

We  will  begin  by  allowing  an  extra  byte  of  storage  whose  value  is  30^^. 
This  byte  will  be  located  just  before  the  buffer  area. 

SPARE:  .BYTE  30^ 

BUFFER:  BLKB  120 

SPRFLG:  BLKB  1 

NUMBER:  BLKB  65 


90 


Z-86  and  8080  Assembly  Language  Programming 


We  will  then  assume  that  the  number  is  input  into  the  buffer  area  beginning 
at  BUFFER  +  0.  Examination  of  the  buffer  contents  will  thus  begin  at  that 
address.  Each  character  in  the  buffer  will  be  examined  in  turn. 

Initialization:  Zero  the  space  flag  (SPRFLG)  and  the  entire  data  area 
reserved  for  NUMBER.  Set  the  HL  and  DE  register  pairs  so  that  both  point  to 
BUFFER  +  0.  Zero  registers  B  +  C  to  be  used  for  counts. 

Presignificance  loop  (repeat  1  and  2  until  a  jump  out  of  the  loop  oc- 
curs ) : 

1 .  Fetch  a  character  from  the  buffer  location  pointed  to  by  the  DE  pair. 

2.  Test  for  one  of  the  following  and  perform  the  corresponding  action 
upon  a  match: 

a.  Space  —  Increment  the  DE  register  pair. 

I 

+ 

b.  —       —  Move  a  1  to  the  sign  descriptor  byte.  Increment  the  DE  register 

pair. 

c.  .  —  Increment  the  DE  register  pair  and  jump  to  the  post-decimal  loop. 

d.  Digit   —  Move  the  character  to  the  location  pointed  to  by  the  HL  pair. 
(0-9)        Increment  both  the  DE  and  -HL  registers.  Increment  the  B 

register.  Jump  to  the  post-significance  loop. 

e.  Any    —  Jump  to  the  termination  segment, 
other 

Post-significance  loop  (repeat  1  and  2  until  a  jump  out  of  the  loop  oc- 
curs): 

1 .  Fetch  a  character  from  the  buffer  location  pointed  to  by  the  DE  pair. 

2.  Test  for  one  of  the  following  and  perform  the  corresponding  action 
upon  a  match: 

a.  ,         —  Increment  the  DE  register  pair. 

b.  —  — -  Move  a  1  to  the  sign  desciptor  byte.  Jump  to  the  termination 

segment. 

c.  .         —  Increment  the  DE  register  pair  and  jump  to  the  post-decimal 

loop. 

d.  Digit  —  Move  the  character  to  the  location  pointed  to  by  the  HL  pair. 
(0-9)       Increment  both  the  DE  and  HL  registers.  Increment  the  B 

register. 

e.  Any   —  Jump  to  the  termination  segment, 
other 

Post-decimal  loop  (perform  1  and  then  repeat  2  and  3  until  a  jump 

out  of  the  loop  occurs): 
L  Check  the  digit  count  in  register  B.  If  it  is  an  odd  number  (bit  0  is  set), 

increment  register  B  and  set  the  spare  flag  (SPRFLG  "^1). 
2.  Fetch  a  character  from  the  buffer  location  pointed  to  by  the  DE  pair. 


Binary  Coded  Decimal  Arithmetic 


91 


3.  Test  for  one  of  the  following  and  perform  the  corresponding  action 
upon  a  match: 

a.  —      —  Move  a  1  to  the  sign  descriptor  byte.  Jump  to  the  termination 

segment. 

b.  Digit  —  Move  the  character  to  the  location  pointed  to  by  the  HL  pair. 
(0-9)      Increment  both  the  DE  and  HL  registers.  Increment  both  the  B 

and  C  registers. 

c.  Any   —  Jump  to  the  termination  segment, 
other 

Termination  segment: 

1.  Check  the  digit  count  in  register  B.  If  it  is  an  odd  number  (bit  0  is  set) 
increment  both  the  B  &  C  registers  and  move  the  value  30^  to  the 
location  pointed  to  by  the  HL  pair. 

2.  Divide  the  contents  of  register  B  by  2  by  shifting  to  the  right  and  store 
this  value  in  size. 

3.  Repeat  for  register  C,  store  in  number  of  digits  to  the  right  of  the 
decimal  point. 

4.  Set  the  HL  register  pair  to  point  to 

a.  BUFFER  +  0  -  if  SPRFLG  =  0 

b.  SPARE  -  if  SPRFLG  =  1 

5.  Use  the  previously  described  translation  routine  to  convert  the  input 
characters  to  BCD.  The  number  of  repetitions  for  the  loop  is  the  value 
in  SIZE. 

Although  this  routine  may  seem  to  be  long  and  complex,  it  is  really 
worth  the  effort  to  encode  and  debug  it.  Once  written,  it  becomes  a  highly 
portable  utility  routine  that  can  be  used  in  any  application  requiring  BCD 
arithmetic. 

Fixed  Point  Addition  and  Subtraction 

We  have  already  seen  how  the  use  of  the  decimal  adjust  instruction  DAA  can 
greatly  simplify  addition  and  subtraction  of  BCD  numbers.  Now  it  is  time  to 
consider  the  subleties  of  decimal  point  alignment  and  discuss  how  a  BCD 
routine  to  add  and  subtract  fixed  point  numbers  might  be  structured. 
First  consider  the  following  addition  operation. 

1.023  +  7.7 

A  routine  that  performs  this  addition  must  take  into  account  the  need  to 
properly  align  the  decimal  point. 

1.023 

+  7.7 
8.723 


92 


Z-80  and  8080  Assembly  Language  Programming 


It  is  also  necessary  to  decide  on  the  location  for  the  result  of  the  operation.  If 
it  is  decided  to  leave  the  result  in  either  the  first  or  the  second  operands,  the 
fact  that  the  result  may  be  larger  than  the  inputs  must  be  taken  into  account 
in  the  algorithm  design.  Lastly,  the  routines  must  take  into  account  the  sign 
of  the  inputs,  since  the  numbers  themselves  are  not  stored  in  any  fashion  such 
as  2's  complement  v^hich  allows  them  to  be  dealt  with  directly. 

The  routines  described  below  will  extend  zeroes  to  the  right  of  the 
decimal  point  of  the  shorter  number  to  solve  the  alignment  problem.  For 
example, 

1.023  +  7.7 

will  become 

1.023 
+  7.700 
8.723 

The  location  of  the  result  will  be  a  totally  separate  result  area.  This  area  will 
act  as  a  buffer  in  the  sense  that  a  second  call  to  the  addition  routine  will 
destroy  the  result  of  the  previous  addition.  So  the  calling  program  will  have  to 
move  the  result  to  the  location  of  its  choice. 

The  sign  of  the  inputs  will  be  taken  into  account  in  the  following 
manner. 

Addition: 

Operands  of  the  same  sign:        Perform    addition    on    the  two 

operands.  Attach  their  common 
sign  to  the  result. 

Operands  of  opposite  sign:        Subtract  the  smaller  from  the 

larger.   Attach  the  sign  of  the 
larger  to  the  result. 

Subtraction: 

Given  operand  1  minus  operand  2,  change  the  sign  of  operand  2  and 
add.  Restore  the  sign  of  operand  2  before  returning  from  the 
subroutine. 

The  whole  subject  of  attaching  the  proper  sign  to  the  result  apparently 
depends  on  the  ability  to  compare  two  BCD  numbers.  Since  these  numbers 
can  be  extremely  long,  such  a  comparison  may  seem  difficult.  In  fact,  it  is  not 
terribly  hard  to  do  this.  Before  a  comparison  is  made,  the  two  numbers  will 
first  be  adjusted  so  they  have  the  same  number  of  bytes  to  the  right  of  the 


If 


Binary  Coded  Decimal  Arithmetic 


93 


decimal  point.  At  this  time  the  size  of  the  two  numbers  can  be  compared.  If 
one  is  longer,  it  is  larger.  Numbers  of  the  same  length  can  be  subjected  to  a 
byte-by-byte  unsigned  compare. 

The  routines  themselves  make  use  of  two  length  indicators.  These  are  the 
lengths  of  the  two  operands  after  decimal  point  adjustment  has  taken  place. 
The  basic  loops  merely  involve  a  straight  add  (or  subtract)  of  the  lowest  order 
byte  and  an  add  (or  subtract)  with  carry  of  every  higher  order  byte  until  the 
shorter  number  is  exhausted.  After  that  point  has  been  reached,  the  routine 
continues  to  add  (or  subtract)  with  carry  using  a  "dummy"  operand  with  a 
zero  value  until  the  longer  number  is  exhausted.  After  each  and  every  ad- 
dition (or  subtraction)  the  decimal  adjust  operation  is  performed. 

Floating  Point  Multiplication 

The  method  to  be  used  in  floating  point  multiplication  parallels  that  used  in 
long-hand  computation. 

7.032 
X  .42 
14064 
28128 
2.95344 

The  size  of  the  result  will  be,  at  most,  the  sum  of  the  sizes  of  the  two  operands. 
The  number  of  bytes  to  the  right  of  the  decimal  point  will  be  exactly  the  sum 
of  the  numbers  of  bytes  to  the  right  of  the  decimal  point  in  the  two  operands. 

To  outline  the  method  to  be  used,  consider  the  two  BCD  operands  as 
strings  in  memory.  The  smaller  operand  will  be  used  as  the  multiplier  and 
will  have  a  pointer  to  its  least  significant  digit's  byte 


Multiplicand 


Multiplier 

Least  significant  digit 


The  digit  in  the  multiplier  will  be  read,  and  the  multiplicand  will  be 
added  into  the  result  that  many  times.  The  addition  will  ignore  the  decimal 
point  in  the  multiplicand.  Then  the  multiplicand  will  be  shifted  to  the  left 
four  bits  (i.e.,  multiplied  by  10),  and  the  next  digit  in  the  multiplier  will  be 
considered.  This  process  will  be  repeated  until  all  of  the  digits  of  the 
multiplier  have  been  used  up.  In  the  process  of  left  shifting  the  multiplicand, 
the  RLD  instruction  will  prove  invaluable. 


94 


Z-Sfiand  8080  Assembly  Language  Programming 


The  sign  of  the  resulting  product  can  easily  be  determined  by  comparing  the 
signs  of  the  operands: 

Operands  Result 

+  +  + 

+  - 

-  + 

-  -  + 
Floating  Point  Division 

Again  the  technique  utilized  will  parallel  that  used  in  long  division.  To  trace 
the  method,  however,  we  will  have  to  analyze  the  thought  processes  used  in 
division  very  carefully.  Consider  first  the  approach  taken  in  performing  the 
following  long  division. 

6.347  I  10.4 

The  first  step  in  performing  this  division  by  hand  would  be  to  shift  the 
decimal  point  three  places  to  the  right  in  both  the  divisor  and  the  dividend. 

6.347.  I  10.400.  =  6347  I  10400. 

Once  this  step  has  been  performed,  the  decimal  point  is  fixed  in  the  result. 
But  in  our  algorithm  it  will  be  the  number  of  bytes  to  the  left  of  the  decimal 
point  that  we  will  want  to  keep  track  of,  since  the  number  of  bytes  to  the  right 
will  depend  on  the  accuracy  with  which  the  calculation  is  performed.  The 
desired  number  of  bytes  of  accuracy  would  have  to  be  input  to  the  subroutine 
as  a  parameter. 

An  outline  of  the  algorithm  follows. 

1 .  Check  the  number  of  bytes  to  the  right  of  the  decimal  point  in  the 
divisor.  If  this  is  nonzero,  multiply  both  dividend  and  divisor  by  100  by  using 
an  eighth  bit  left  shift.  Repeat  this  step  until  the  divisor  has  no  digits  to  the 
right  of  the  decimal  point.  The  eight  bit  shift  can  be  accomplished  by  simply 
adding  the  digits  00  to  the  end  of  the  number  and  adjusting  the  decimal 
point. 

2.  Subtract  the  number  of  bytes  to  the  right  of  the  decimal  point  from 
the  total  number  of  bytes  to  obtain  the  number  of  bytes  to  the  left  of  the 
decimal  point  in  the  dividend. 

3.  Now  create  the  quotient  by  performing  the  following  loop  the  number 
of  times  equal  to  the  desired  accuracy  as  input.  Note  that  using  this  system 
leading  zeroes  will  be  counted  as  digits  of  accuracy.  The  number  of  bytes  of 
accuracy  would  be  obtained  by  adding  to  the  end  of  the  dividend  the  required 
number  of  00  bytes  to  make  its  total  length  equal  to  the  desired  accuracy. 
Begin  the  loop  by  left  shifting  the  dividend  four  bits  and  taking  only  the  first 
byte  as  the  assumed  size  of  the  dividend. 


Binary  Coded  Decimal  Arithmetic 


95 


a.  Subtract  the  divisor  from  the  assumed  size  of  the  dividend.  Keeping  a 
count  of  the  number  of  subtractions  performed,  repeat  until  the  result 
goes  negative.  At  that  point,  add  the  divisor  back  and  decrement  the 
subtraction  count.  Output  the  count  as  a  digit  of  the  quotient. 

b.  Left  shift  the  dividend  four  bits,  but  maintain  the  same  assumed  size  of 
the  dividend.  Repeat  step  a. 

c.  Left  shift  the  dividend  four  bits  and  increase  the  assumed  size  of  the 
dividend  by  one  byte.  Repeat  steps  a-c  until  the  desired  number  of  bytes 
of  accuracy  have  been  obtained. 

4.  When  the  entire  quotient  has  been  formed,  delete  leading  00  bytes 
and  adjust  the  decimal  point  accordingly. 

Exercises 

1 .  Write  a  subroutine  which  will  take  as  input  a  number  in  character  form  in  a 
buffer  and  produce  as  output  the  BCD  value  of  the  number. 

2.  Write  a  subroutine  which  will  perform  a  fixed  point  addition  of  two  BCD 
numbers. 

3.  Write  a  subroutine  which  will  perform  a  fixed  point  subtraction  of  two  BCD 
numbers. 

4.  Write  a  subroutine  which  will  perform  a  floating  point  multiplication  of  two 
BCD  numbers. 

5.  Write  a  subroutine  which  will  perform  a  floating  point  division  of  two  BCD 
numbers. 


when  time  is  important 


In  this  chapter  we  will  be  dealing  with  two  totally  separate  types  of  time.  On 
the  one  hand,  we  will  discuss  how  to  optimize  program  development  time 
That  is,  how  to  get  the  most  from  the  human  hours  that  go  into  program 
design,  coding,  testing,  and  debugging.  On  the  other  hand,  we  will  consider 
how  to  minimize  machine  execution  time  in  applications  where  run  speed  is 
critical. 

An  Approach  to  Program  Development 

George  has  just  been  given  a  job  contract  to  develop  a  complete 
microcomputer  program  for  a  talent  agency.  He  talks  to  the  owner  and  she 
spends  an  hour  and  half  telling  him  all  the  things  she  wants  the  program  to 
do.  The  task  seems  frightening,  but  he  will  make  enough  money  to  pay  for  his 
complete  computer  system  five  times  over. 

At  home,  perched  at  his  desk  and  ready  to  work,  he  drags  out  all  the 
notes  he  took  at  his  interview.  The  first  thing  he  will  want  to  do  is  ('i^  begin 
with  a  clear  idea  of  what  the  program  is  to  accomplish.  George  determines 
that  the  talent  agency  wants  the  program  to  maintain  a  complete,  up-to-date 
file  containing  name,  address,  phone  number,  and  abilities  profile  for  each  of 
its  clients.  The  agency  would  like  to  give  an  casting  director  an  immediate  yes 
or  no  answer  as  to  whether  they  have  a  client  on  file  with  a  given  abilities 
profile.  If  the  director  wants  to  make  an  interview  appointment,  the  agency 
will  need  to  get  a  display  of  the  names,  addresses,  and  phone  numbers  of  all 
clients  who  fit  the  profile.  With  the  total  task  summarized,  George's  thoughts 
are  already  turning  to  the  second  step:  (2)  divide  the  total  task  into  any 
isolatable  sub-tasks. 

He  can  identify  three  clearly  distinguishable  sub-tasks  in  the  talent 
agency  program: 

a.  keeping  the  client  file  current 

b.  performing  a  search  for  a  given  profile 

c.  listing  name,  address,  phone  on  matches 

Now  George  is  really  clicking,  ideas  are  starting  to  pour  in.  He  jots  dovm  on 
scratch  paper  a  few  ideas  he  doesn't  want  to  forget.  For  instance,  the  thought 


96 


When  Time  Is  Important 


97 


just  occurred  to  him  that  all  the  information  the  agency  needs  to  know  about 
its  people  can  be  contained  in  a  single  byte.  But  George  doesn't  get  carried 
away  from  his  planning.  He  moves  right  into  the  third  step:  (3)  concentrating 
on  a  single  one  of  the  sub-tasks,  repeat  step  2.  Repeat  2  and  3  until  all  of  the 
program  modules  have  been  designed. 

George  zeroes  in  on  the  problem  of  keeping  the  client  file  current.  He 
divides  it  as  follows. 

A.  adding  new  clients  and  their  profiles 

B.  updating  a  field  in  a  client  record 

C.  deleting  former  clients  and  their  profiles 

The  problem  of  adding  new  clients  and  their  profiles  becomes  the  next  series 
of  tasks. 

i.  getting  a  new  node  area 

ii.  filling  in  name,  address,  and  phone  fields 

iii.  collecting  employee  profile  information  and  organizing  it  into  a  descrip- 
tive byte 

Getting  a  new  node  is  no  problem.  George  can  easily  adapt  a  subroutine  he 
wrote  long  ago  to  do  this.  Filling  in  name,  address,  and  phone  fields  he  had 
also  done  before.  George  has  a  collection  of  message  input  and  output 
subroutines  to  draw  on.  So  the  only  problem  George  faces  right  now  is 
collecting  and  organizing  profile  information.  Deeply  absorbed  in  his  work, 
George  has  completely  forgotten  how  awesome  the  task  appeared  at  first.  The 
profile  task  still  needs  narrowing  down.  He  refers  to  his  notes  and  decides  that 
he  can  use  his  standard  I/O  subroutines  to  collect  the  answers  to  a  series  of 
questions.  He'll  convert  a  yes  to  a  1  and  a  no  to  a  0.  Going  into  the  routine 
he'll  clear  the  accumulator.  Then  he'll  set  the  low  order  bit  accordingly  and 
shift  one  to  the  left  before  the  next  question. 

Before  too  long,  and  well  before  the  design  deadline,  George  has  the 
complete  program  design.  He  knows  what  his  data  will  look  like  in  memory. 
He  knows  what  routines  and  subroutines  are  needed  for  the  job  and  has  a 
good  idea  of  what  machine  capabilities  he  will  utilize  in  the  performance  of 
each  task.  He  has  a  complete  block  diagram  of  his  program  showing  which 
routines  call  what  subroutines.  A  portion  of  George's  block  diagram  is  shown 
on  the  following  page. 

Through  all  this  design  effort,  George  has  not  written  a  single  line  of 
assembly  language  code.  With  the  design  complete,  though,  he's  ready  to 
begin  coding.  It's  no  haphazard  guess  as  to  what  to  code  first.  George  is 
following  the  fourth  step:  (4)  code  the  main  driver  first,  then  all  first  level 
subroutines  and  so  on,  coding  from  the  top  doxvn  to  the  lowest  level 
subroutine.  Coding  takes  a  long  time.  A  few  problems  arise  for  George,  but 
he  discovers  that  even  though  he  has  to  adjust  his  design  a  little,  he  never 


98 


Z-80  and  8680  Assembly  Language  Programming 


seems  to  have  to  make  many  changes  to  code  he  has  already  written.  That's 
the  top-down  approach  working  for  him.  If  he'd  begun  coding  from  the 
lowest  level  subroutine  up,  he  would  be  spending  half  his  time  erasing  code 
and  tracking  down  the  repercussions  of  minor  changes. 


mam 

program 

driver 


update 
driver 


search 
for 

profile 

listing 
matches 


client 
addition 


record 
change 

client 
deletion 


get 
node 


name/ 

address 

phone 


client 
profile 


output 
message 

input 
message 

output 

message 

input 
message 


George  is  doing  more  than  just  writing  code  right  now.  He  is 
documenting  every  routine  he  writes.  Long  ago  he  formed  the  habit  of 
commenting  every  line  of  assembly  code.  SET  5,D  won't  give  you  any  clues  as 
to  what  you  were  up  to  when  you  wrote  it  two  weeks  ago.  But  line  comments 
aren't  enough  for  a  project  of  this  size.  George  keeps  a  whole  block  of  com- 
ments as  a  header  to  each  subroutine.  He  always  includes 


NAME: 

FUNCTION: 
CALLED  BY: 
CALLS: 
ARGUMENTS: 


The  complete  name  of  the  routine  with  acronyms 
expanded  in  full. 

A  brief  description  of  the  purpose  of  the  routine. 
The  names  of  all  the  routines  that  call  this  routine. 
The  names  of  all  the  routines  that  this  routine  calls. 
Any  data  that  is  passed  to  this  routine  in  a  register 
or  returned  from  this  routine  in  a  register  is  clearly 
spelled  out. 


When  Time  Is  Important 


99 


George  never  omits  any  of  these  items.  For  instance,  in  his  main  program 
driver  he  has  the  Hne 

CALLED  BY:  NONE 

Then  he  knows  that  no  item  was  forgotten.  George  also  carefully  documents 
the  data  structures  he  is  using.  The  name,  the  size,  the  function,  and  the 
alignment  of  all  variables  and  tables  are  included. 

Finally  the  job  of  coding  is  finished  and  George  surveys  the  job  with 
satisfaction.  The  program  fills  a  three  ring  binder.  He  has  sections  separated 
by  dividers  for  all  his  documentation  and  for  each  subroutine.  Now  he  is 
ready  to  begin  to  assemble  the  code  and  test  it.  George  is  quite  excited  about 
the  project.  He's  itching  to  enter  all  the  code,  assemble  it,  and  let  it  rip.  But 
he  knows  that  method  would  only  give  him  a  big  letdown.  Even  the  smallest 
subroutine  isn't  guaranteed  to  run  the  first  time.  It  has  to  be  debugged,  and 
with  a  project  of  any  size,  that  can  be  either  a  nightmare  or  a  smooth,  orderly 
procedure,  depending  on  the  way  it  is  approached.  So  George  won't  let  his 
enthusiasm  run  away  with  him.  Instead  he'll  follow  the  fifth  step:  (5)  assemble 
and  test  the  lowest  level  subroutines  first,  working  from  the  bottom  up. 

George  begins  with  the  utility  routines  he's  adapting  from  previous 
programs.  His  basic  I/O  routines  really  get  the  once-over.  Every  time  George 
tests  a  routine,  he  uses  the  same  basic  plan.  He  is  always  careful  to  include  test 
cases  that  will  exercise  every  branch.  He  wants  to  be  sure  that  every  line  of 
code  is  executed  during  the  test  phase.  When  he  feels  confident  that  the 
jumps  are  jumping  properly  and  the  loops  are  looping,  George  is  still  not 
ready  to  certify  the  routine  as  fully  debugged.  What  if  bad  data  comes 
through?  What  if  a  clerk  types  a  name  where  a  number  should  have  been 
entered?  Will  the  whole  program  come  to  a  crashing  halt?  George  has  in- 
cluded data  validation  checks  in  his  subroutine  designs  wherever  a  problem 
could  cause  a  crash.  Now,  during  debug,  he  will  try  out  the  weirdest  of  the 
weird  data  inputs  to  see  what  effects  they  have  on  the  system.  If  an  empty 
array  is  passed,  will  the  loop  droop?  If  the  program  runs  out  of  space  for  more 
clients,  will  it.ignore  the  problem  and  wipe  out  anything  in  its  way? 

If  George  discovers  that  he's  done  a  "jump  on  zero  "  when  he  wanted  a 
"jump  on  a  nonzero  "  or  some  such  error,  he  can  alter  the  program. 

LOG  204E  =  CA  4323  (jump  on  zero  to  2343) 

George  can  simply  change  one  instruction  by  TE  at  204E  to  a  D2,  so 

LOG  204E  =  D24323  (jump  on  nonzero) 

Such  changes  are  very  simple  when  the  corrected  instruction  is  the  same 
length  as  the  original  instruction. 

If  George  discovers  that  he's  got  an  instruction  in  the  program  that  he 
doesn't  want,  he  can  just  substitute  NOP  instructions  in  its  place.  For 
example,  to  remove 


100 


Z-Sdand  8080  Assembly  Language  Programming 


LOC214B  =  CD3750  (call  loc.  5037) 
replace  it  with  three  NOPs: 

LOC  214B  =  00 
214C  =  00 
214D  =  00 

Now  what  if  George  discovers  he's  forgotten  an  instruction  that  should  be 
there?  He  could  stop  his  debugging  in  midstream  while  he  corrects  the 
program  and  reassembles,  or  he  could  simply  make  a  "patch."  A  patch  is  a 
program  repair  that  involves  making  an  unconditional  jump  out  to  an  unused 
location  in  memory  (called  the  patch  area).  There,  any  omitted  instructions 
can  be  hand  assembled  and  listed  directly  in  machine  code  before  making  an 
unconditional  jump  back  to  program  area.  There  are  four  steps  involved. 

1 .  Create  a  jump  out  to  the  patch  area  "C3  "  by  replacing  three  bytes 

in  the  program.  [If  you  replace  only  part  of  an  instruction,  be  sure  to 
replace  the  rest  of  it  with  NOP(s).] 

2.  In  the  patch  area  replace  the  instruction(s)  removed  for  the  jump. 

3.  Enter  the  missing  instruction(s)  in  machine  code. 

4.  Code  a  jump  back  to  the  program  area  at  the  end  of  the  patch. 

A  patch  log  which  shows  all  changes  to  the  program  made  during  debug  can 
prove  to  be  invaluable. 

Only  when  he's  convinced  that  the  routine  is  uncrashable  does  George 
certify  it  complete  and  go  on  to  the  next.  As  new  routines  are  debugged,  they 
are  combined  with  the  previous  ones,  gradually  building  toward  the  complete 
system.  When  at  last  the  day  comes  that  the  driver  takes  off  and  drives, 
George  knows  he's  got  a  winner.  He  takes  a  well-earned  couple  of  days  off 
before  the  final  work  on  the  system. 

Yes,  there's  more.  George  wants  to  be  sure  the  program  will  work  under 
field  conditions,  so  he  copies  names  from  the  phone  book  and  invents  profiles 
randomly  until  he  has  as  many  "clients"  on  his  system  as  the  agency  will  have. 
Will  searches  slow  to  unbearable  waits  under  a  heavy  load?  Will  an  agency 
clerk  give  a  yes  to  a  casting  director  only  to  discover  that  there's  only  one 
client  with  that  profile,  and  his  address  and  phone  number  are  garbled? 
George  needs  to  know  the  answers.  Can  he  do  the  search  if  a  director  says,  "I 
don't  care  if  it's  a  man,  woman,  or  goat  —  just  send  me  someone  who  can  act!" 

Fortunately,  George  did  his  work  well  and  his  system  responds  gracefully 
to  the  most  outlandish  inputs.  It's  time  for  a  party!  But  soon  after,  he's  back  to 
work.  Still?  Yes,  George  has  to  write  his  user  documentation.  Complete,  clear, 
easy-to-follow  directions  must  be  prepared  for  each  type  of  entry  or  inquiry  to 
the  system.  George  doesn't  assume  any  knowledge  on  the  part  of  the  operator. 
He  makes  the  documentation  complete  enough  for  the  first-time  user,  but  at 


When  Time  Is  Important 


101 


the  same  time,  concise  enough  to  provide  quick  reference  for  the  experienced 
user. 

Needless  to  say,  now  that  George  has  delivered  the  completed  system  to 
the  talent  agency,  he  feels  confident  that  it  will  serve  them  well.  And  George 
.  .  .  well,  he's  vacationing  in  Bermuda. 

Optimizing  Run  Time 

It  is  in  pursuit  of  speed  that  most  programmers  turn  to  assembly  language 
code.  The  interpretive  nature  of  BASIC  slows  execution  to  the  point  where 
complex  programs  run  at  an  intolerably  slow  pace.  For  most  applications, 
merely  switching  to  assembly  language  provides  the  needed  speed  up.  Oc- 
casionally, however,  the  application  is  so  demanding  and  so  time-critical  that 
the  use  of  assembly  code  in  itself  is  not  enough.  In  such  applications  it  is 
necessary  to  identify  those  segments  of  code  which  must  be  executed 
repeatedly  within  a  short  time  frame,  perhaps  thousands  of  repetitions  must 
be  made  within  a  minute  or  so.  Once  the  real  bottlenecks  have  been  isolated, 
these  routines  can  be  optimized. 

Optimization  of  code  requires  an  awareness  of  the  time  the  computer 
spends  in  executing  a  particular  type  of  instruction.  The  time  is  not  so  much 
the  absolute  time  required  for  each,  but  more  important,  is  the  relative 
execution  times  of  the  various  instructions.  We  will  measure  relative 
execution  times  in  terms  of  a  "T-state."  A  T-state  corresponds  to  a  single 
clock  pulse  in  the  central  processing  unit.  The  actual  time  required  for  a  T- 
state  depends  on  the  clock  speed  of  the  individual  microprecessor.  For  in- 
stance, if  the  microprocessor  is  running  at  1  MHz  (one  megahertz),  then  there 
are  one  million  T-states  per  second.  A  4  MHz  clock  rate  produces  four  million 
T-states  per  second. 

When  trying  to  decide  whether  optimization  is  worthwhile,  remember 
that  T-states  must  be  saved  by  the  millions  to  cut  seconds  off  execution  time. 

The  instruction  times  for  each  instruction  as  measured  in  T-states  are 
included  in  the  instruction  summary  appendix.  The  execution  times  fall  into 
basic  groups  depending  on  the  location  of  the  operands.  The  fastest  type  of 
instruction,  for  instance,  operates  on  two  operands  which  are  both  located  in 
eight  bit  registers.  The  chart  on  page  102  summarizes  the  instruction  times 
for  eight  bit  operands  based  on  operand  location. 

Here  we  see  the  characteristic  longer  execution  times  for  the  indexed 
instructions  which  typically  take  2.5  to  nearly  6  times  longer  than  the 
corresponding  instruction  in  an  eight  bit  register.  To  show  how  optimization 
can  take  place,  suppose  the  code  you  were  trying  to  speed  up  used  an  indexed 
storage  location  to  hold  a  temporary  result  in  a  computation.  To  put  the 
value  out  in  memory  would  require  19  T-states.  To  retrieve  it,  another  19,  for 
a  total  of  38.  Saving  the  same  value  in  an  eight  bit  register  takes  four  T-states 


102 


Z-8d  and  808d  Assembly  Language  Programming 


and  four  to  retrieve  it,  for  a  total  cost  of  eight  T-states.  If  that  register  is  free, 
we've  found  a  way  to  save  30  T-states. 


Operation 

r 

(HL) 

n 

(lY  +  d) 
(IX +  d) 

(nn) 

LOAD 
ADD 

SUBTRACT 

AND 

OR 

XOR 

COMPARE 

4 

7 

7 

19 

13* 

INCREMENT 
DECREMENT 

4 

11 

23 

ROTATE 
SHIFT 
SET  BIT 
RESET  BIT 

8t 

4 

15 

23 

BIT  TEST 

8 

12 

20 

♦LOAD  only. 
fExcept  accumulator. 


Exercise 

1.  As  a  programmer,  you  have  now  had  numerous  examples  of  code  written  by 
and  for  you.  You  should  by  now  have  investigated  the  I/O  techniques  used  in 
your  monitor  and  learned  the  key  words  your  assembler  needs  to  see  to  locate 
a  program  at  a  fixed  spot  in  memory  and  to  reserve  and  name  storage 
locations.  If  you  have  not  already  done  so,  it's  time  to  learn  how  to  create  a 
text  file  on  your  system  and  how  to  assemble  and  load  a  program.  We  have 
just  finished  discussing  techniques  for  organizing  an  approach  to  large 
programming  projects.  In  short,  you  should  now  have  all  the  tools  necessary 
to  tackle  a  programming  project  of  your  own  design. 


APPENDIX  A 
8(3O0/ZILOG  MNEMONICS  CONVERSION 

SYMBOLS  USED 

SYMBOL  OPERATION 

r  one  of  the  8-bit  registers  A,B,C,D,E,H,L 

n  any  8-bit  absolute  value 

ii  an  index  register  reference,  either  X  or  Y 

d  an  8-bit  index  displacement,  where  -128<  d<  127 

zz  B  for  the  BC  register  pair,  D  for  the  DE  pair 

nn  any  16-bit  value,  absolute  or  relocatable 

rr  B  for  the  BC  register  pair,  D  for  the  DE  pair,  H  for  the  HL  pair, 

SP  for  the  stack  pointer 

qq  B  for  the  BC  register  pair,  D  for  the  DE  pair,  H  for  the  HL  pair, 

rSW  for  the  A/Flag  pair 

s  any  of  r  (defined  above),  M,  or  d(ii) 

IFF  Interrupt  flip-flop 

CY  carry  flip-flop 

ZF  zero  flag 

tt  B  for  the  BC  register  pair,  D  for  the  DE  pair,  SP  for  the  stack 

pointer,  X  for  index  register  IX 

uu  B  for  the  BC  register  pair,  D  for  the  DE  pair,  SP  for  the  stack 

pointer,  Y  for  index  register  lY 

b  a  bit  position  in  an  8-blt  byte,  where  the  bits  are  numbered  from 

right  to  left  0  to  7 

PC  program  counter 

b{n}  bit  n  of  the  8-blt  value  or  register  v 

w/H  the  most  significant  byte  of  the  16-bit  value  or  register  w 

w/L  the  least  significant  byte  of  the  16-blt  value  or  register  w 

Iv  an  input  operation  on  port  v 

Ov  an  output  operation  on  port  v 

w      V  the  value  of  w  is  replaced  by  the  value  of  v 

w       V  the  value  of  w  is  exchanged  with  the  value  of  v 


103 


8  BIT  LOAD  GROUP 


8080 

MNEMONIC 
MOV  r,r' 
MOV  r,M 
MOV  r,d(ii) 
MOV  M,r 
MOV  d(il),r 
MVI  r.n 
MVI  M,n 
MVI  d(ii),n 
LDA  nn 
STA  nn 
LDAX  zz 
STAX  zz 
LDA  I 
LDAR 
STAI 
STAR 


OPERATION 
r  ^  r' 
r  ^  (HL) 
r  ^  (il+d) 
(HL)  -<-  r 
(il+d)  r 
r  -<-  n 
(HL)  -f-  n 
(li+d)  ^  n 
A  (nn) 
(nn)  *-  A 
A  (zz) 
(zz)  A 
A  ^  I 
A  ^  R 
I  ^  A 
R  ^  A 


ZILOG  //  OF        //  OF 

MNEMONIC  BYTES      T  STATES 

LD  r,r'  1  4 

LD  r,(HL)  1  7 

LD  r/Iil+d)  3  19 

LD  (HL),r  1  7 

LD  (Ili+d),r  3  19 

LD  r,n  2  7 

LD  (HL),n  2  10 

LD  (Iil4tl),n  4  19 

LD  A,(nn)  3  13 

LD  (nn),A  3  13 

LD  A,(zz)  1  7 

LD  (zz),A  1  7 

LD  A,I  2  9 

LD  A,R  2  9 

LD  I,A  2  9 

LD  R,A  2  9 


16  BIT  LOAD  GROUP 


8080 

MNEMONIC 
LXI  rr , nn 
LXI  11, nn 
LBCD  nn 

LDED  nn 

LHLD  nn 

LIXD  nn 


OPERATION 
rr  nn 

11  ■<-  nn 

B  ^  (nn+1) 
C  (nn) 

D  *-  (nn+1) 
E  ^  (nn) 

H  *-  (nn+1) 
L  (nn) 

IX/H  (nn+1) 
IX/L  ^  (nn) 


ZILOG 
MNEMONIC 

LD  rr,nn 

LD  11, nn 

LD  EC, (nn) 

LD  DE, (nn) 

LD  HL, (nn) 

LD  IX, (nn) 


if  OF 
BYTES 

3 

4 

4 


//  OF 

T  STATES 
1«) 
14 
20 

20 

16 


20 


104 


LIYD  nn 

lY/H 
lY/L  ^ 

(nn+1) 
(nn) 

LD  IY,(nn) 

4 

20 

LSPD  nn 

SP/H 
SP/L  ^ 

(nn+1) 
(nn) 

LD  SP,(nn) 

4 

20 

SBCD  nn 

(nn+1) 
(nn) 

^  B 
^  C 

LD  (nn),BC 

4 

20 

SDED  nn 

(nn+1) 
(nn) 

D 

■>-  E 

LD  (nn),DE 

4 

20 

SHLD  nn 

(nn+1) 
(nn) 

H 
L 

LD  (nn),HL 

3 

16 

SIXD  nn 

(nn+1) 
(nn) 

IX/H 
IX/L 

LD  (nn),IX 

4 

20 

SIYD  nn 

(nn+1) 
(nn) 

lY/H 
^  lY/L 

LD  (nn),IY 

4 

20 

SSPD  nn 

(nnfl) 
(nn) 

SP/H 
SP/L 

LD  (nn),SP 

4 

20 

SPHL 

SP  ^  HL 

LD  SP,HL 

1 

6 

SPIX 

SP  ^  IX 

LD  SP,IX 

2 

10 

SPIY 

SP  ^  lY 

LD  SP.IY 

2 

10 

PUSH  qq 

(SP-1) 
(SP-2) 
SP 

-  qq/H 
^  qq/L 
SP-2 

PUSH  qq 

1 

11 

PUSH  li 

(SP-1) 
(SP-2) 
SP 

■«-  li/H 
^  li/L 
SP-2 

PUSH  11 

2 

15 

POP  nn 

qq/H  * 
qq/L  ^ 
SP  ^ 

(SP-1) 
(SP) 
SP-2 

POP  nn 

1 

10 

POP  11 

li/H 
11/L 
SP 

(SP+1) 

(SP) 

SP+2 

POP  11 

2 

14 

EXCHANGE,  BLOCK  TRANSFER,  AND  SEARCH  GROUP 


8080  ZILOG  9  OF  #  OF 

MNEMONIC  OPERATION  MNEMONIC  BYTES  T  STATES 

XCHG  HL  <-*-l)E  EX  DE,HL  1  4 

EXAF  PSW  *-^PSW'  EX  AF,AF'  1  4 

EXX  BCDEHL  ---^BCDEHL'  EXX  1  4 


105 


H  ^(SP+1)  EX  (SP)  ,HL 

L  -(->-(SP) 

IX/H  ^(SP+1)  EX  (SP),IX 

IX/L  ^(SP) 

lY/H  ^(SP+1)  EX  (SP),IY 

lY/L  ^(SP) 

(DE)  ^  (HL)  LDI 
DE    <-  DE+1 
HL    ■<-  HL+1 
BC    ^  BC-1 

repeat  LDI  until  BC=0  LDIR 

(DE)  *    (HL)  LDD 

DE  ^  DE-1 
HL  HL-1 

BC  ^  BC-1 

repeat  LDD  until  BC=0  LDDR 

A    -   (HL)  CPI 
HL  *■  HL+1 
BC  1-  BC-1 

repeat  CCI  until  A=(HL)  CPIR 
or  BC=0 

A    -  (HL)  CPD 
HL  *■  HL-1 
BC  BC-1 

repeat  CCD  until  A=(HL)  CPDR 
or  BC=0 


2 
2 


2 
2 


19 


23 


23 


16 


21/16 
16 


21/16 
16 

21/16 
16 

21/16 


8  BIT  ARITHMETIC  AND  LOGICAL 


OPERATION 

A  ^  A  +  r 

A      A  +  (HL) 

A      A  +  (ii+d) 

A      A  +  n 

A  ^  A  +  s  +  CY 


ZILOG 
MNEMONIC 

ADD  A,r 

ADD  A,(HL) 

ADD  A, (Ill+d) 

ADD  A,n 

ADC  A,s 


#  OF         //  OF 
BYTES       T  STATES 

1  4 

1  7 

3  19 

2  7 

As  shovm  for  ADD 
instruction 


A  ^  A  +  n  +  CY 
A  +-  A  -  s 


ADC  A,n 

SUB  s 


106 


SUI  n 
SBB  s 
SBI  n 
ANA  s 
ANI  n 
ORA  s 
ORI  n 
XRA  s 
XRI  n 
QIP  s 
CPI  n 
INR  r 
INR  M 
INR  d(il) 
DCR  r 
DCR  M 
DCR  d(li) 


A  ^  A  -  n 

A  ^  A  -  s  -  CY 

A  ^  A  -  n  -  CY 

A  A  A  s 

A  ^  A  A  n 


A 
A 
A 
A 
A 
A 


A  V  s 
A  V  n 

3 

A  n 


-  s 


-  n 


r      r  +  1 

(HL)  *-  (HL)  +  1 

(11+d)  ^  (li+d)  +  1 

r      r  -  1 

(HL)  *-  (HL)  -  1 

(il+d)  ^  (il+d)  -  1 


SUB  n 
SBC  A,s 
SBC  A,n 
AND  s 
AND  n 
OR  s 
OR  n 
XOR  s 
XOR  n 
CP  s 
CP  n 
INC  r 
INC  (HL) 
INC  (lil+d) 
DEC  r 
DEC  (HL) 
DEC  (lii+d) 


GENERAL  PURPOSE  ARITHMETIC  AND  CONTROL  GROUP 


8080 
MNEMONIC 

DAA 


CMA 

NEC 

CMC 

SIC 

NOP 

HLT 

DI 

EI 


OPERATION 

convert  A  to  packed  BCD 
after  an  add  or  subtract 
of  packed  BCD  operands 


A 
A 


■^A 
-A 


CY  m:y 

CY  1 

no  operation 

halt 

IFF  *-  t) 

IFF  *-  1 


ZILOG 
MNEMONIC 

DAA 


GPL 

NEC 

CCF 

SCF 

NOP 

HALT 

DI 

EI 


//  OF 
BYTES 


//  OF 

T  STATES 


1 
2 
1 
1 
1 
1 
1 
1 


4 
8 

4 
4 
4 
4 
4 


107 


IM0 
IMl 
IM2 


Interrupt  mode  0 
interrupt  mode  1 
Interrupt  mode  2 


IM  0 
IM  1 
IM  2 


2 
2 
2 


8 
8 
8 


16  BIT  ARITHMETIC  GROUP 


8080 

MNEJ^ONIC 
DAD  rr 
DADC  rr 
DSBC  rr 
DADX  tt 
DADY  uu 
INX  rr 
INX  li 
DCX  rr 
DCX  11 


OPERATION 

HL  ^  HL  +  rr 

HL      HL  +  rr  +  CY 

HL      HL  -  rr  -  CY 

IX      IX  +  tt 

lY  ^  lY  +  uu 

rr      rr  +  1 

11  ^  11  +  1 

rr  -<-  rr  -  I 

11  ^  11  -  1 


ZILOG 
MNEMONIC 

ADD  HL.rr 

ADC  HL.rr 

SBC  HL.rr 

ADD  IX, tt 

ADD  IY,uu 

INC  rr 

INC  11 

DEC  rr 

DEC  11 


//  OF 
BYTES 

1 

2 

2 

2 

2 

1 

2 

1 

2 


if  OF 

T  STATES 
11 
15 
15 
15 
15 

6 
10 

6 
10 


ROTATE  AND  SHIFT  GROUP 


8080 

MNEMONIC 
RLC 


OPERATION 


A 


ZILOG 
MNEMONIC 

RLCA 


//  OF 
BYTES 


#  OF 

T  STATES 


RAL 


CY  ^  7      ^  0 


1 


RLA 


RRC 


L|7      *  0lJv 


0}Jv[cy] 


RRCA 


RAR 


c 


7^0 


CY 


i] 


RRA 


RLCR  r 

RLCR  M 
RLCR  d(ii) 


Same  diagram  as 
for  RLC 


RLC  r 

RLC  (HL) 
RLC  (Ill+d) 


2 
4 


8 

15 

23 


108 


RALR  s 


RRCR  s 


RARR  8 


SLAR  s 


Same  diagram  as 
for  RAL 

Same  diagram  as 
for  RRC 

Same  diagram  as 
for  RAR 


CY 


0^0 


RL  s 


RRC  s 


RR  s 


SLA  s 


Same  as  for  RLCR 
instruction 


SRAR  s 


SRLR  s 


RLD 


RRD 


0  ■>  CY 


0-»  I  7      -»    0  I    I  CY 

s 


A     17    4l3  0 


(HL) l7    4l3  0 


tzzr 


A     17    4l3  0 


r 


(HL) |7     413  0 


SRA  s 


SRL  s 


RLD 


RRD 


L-ZJ 

BIT  SET,  RESET,  AND  TEST  GROUP 


18 


18 


8080 

MNEMONIC 

OPERATION 

ZILOG 
MNEMONIC 

//  OF 
BYTES 

//  OF 

T  STATES 

BIT  b,r 

ZF    ■<-  'vr{b} 

BIT  b,r 

2 

8 

BIT  b,M 

ZF    +  %(HL){b} 

BIT  b,(HL) 

2 

12 

BIT  b,d(li) 

ZF    ^  -x-dll-fdXb} 

BIT  b,(Iil+d) 

4 

20 

SET  b,r 

r{b}-^  1 

SET  b,r 

2 

8 

SET  b,m 

(HL){b}  ^  1 

SET  b,(HL) 

2 

15 

SET  b,d(ll) 

(Ili+d){b}  +-  1 

SET  b,(Ill+d) 

4 

23 

RES  b,s 

S{b}  ^  0 

RES  b,s 

Same  as  for  SET 
Instruction 

JUMP 

GROUP 

8080 
MNEMONIC 

OPERATION 

MNEMONIC 

■  //  OF 
BYTES 

#  OF 

T  STATES 

JMP  nn 

PC  -<-  nn 

JP  nn 

3 

10 

JZ  nn 

If  zero,   then  JMP 

JP  Z.nn 

3 

10 

else  continue 


109 


JNZ  nn 
JC  nn 
JNC  nn 
JPO  nn 
JPE  nn 
JP  nn 
JM  nn 
JO  nn 
JNO  nn 
JMPR  nn 

JRZ  nn 

JRNZ  nn 
JRC  nn 
JRNC  nn 
DJNZ  nn 

PCHL 
PCIX 
PCIY 


If  not  zero 

If  carry 

if  not  carry 

if  parity  odd 

if  parity  even 

if  sign  positive 

if  sign  negative 

If  overflow 

if  no  overflow 

PC      PC  +  e 

where  e  =  nn  -  PC 
-126<  e<  129 

if  zero,   then  JMPR 
else  continue 

if  not  zero 

if  carry 

If  not  carry 

B  ^  B  -  1 

if  B=0  then  continue 
else  JMPR 

PC  1-  HL 

PC  ^  IX 

PC  U 


JP  NZ,nn 
JP  C,nn 
JP  NC,nn 
JP  PO.nn 
JP  PE,nn 
JP  P,nn 
JP  M,nn 
JP  PE,nn 
JP  PO,nn 
JR  e 

JR  Z,e 

JR  NZ,e 
JR  C,e 
JR  NC,e 
DJNZ  e 

JP  (HL) 
JP  (IX) 
JP  (lY) 


3 
3 
3 
3 
3 
3 
3 
3 
3 
2 


2 
2 
2 
2 

1 

2 
2 


10 
10 
10 
10 
10 
10 
10 
10 
10 
12 

7/12 

7/12 
7/12 
7/12 

8/13 

4 
8 
8 


CALL  AND  RETURN  GROUP 


8080 

MNEMONIC 
CALL  nn 


CZ  nn 

CNZ  nn 
CC  nn 


OPERATION 

(SP-1)  -  PC/H 

(SP-2)  ^  PC/l 

SP  SP-2 

PC        -(-  nn 

if  zero,   then  CALL 
else  continue 

if  not  zero 

if  carry 


ZILOG 
MNEMONIC 

CALL  nn 


CALL  Z,nn 

CALL  NZ.nn 
CALL  C,nn 


0  OF 
BYTES 


3 
3 


//  OF 

T  STATES 
17 


10/17 

10/17 
10/17 


110 


CNC  nn 

If 

not  carry 

CALL  NC.nn 

3 

10/17 

CPO  nn 

If 

parity  odd 

CALL  PO.nn 

3 

10/17 

CPE  nn 

if 

parity  even 

CALL  PE.nn 

3 

10/17 

CP  nn 

If 

sign  positive 

CALL  P,nn 

3 

10/17 

CM  nn 

if 

sign  negative 

CALL  M,nn 

3 

10/17 

CO  nn 

If 

overflow 

CALL  PE,nn 

3 

10/17 

CNO  nn 

if 

no  overflow 

CALL  PO,nn 

3 

10/17 

RET 

PC/H  (SP+1) 
PC/L  ^  (SP) 
SP  SP+2 

RET 

10 

RZ 

if  zero,   then  RET 
else  continue 

RET  Z 

5/11 

RNZ 

if 

not  zero 

RET  NZ 

5/11 

RC 

if 

carry 

RET  C 

5/11 

RNC 

if 

not  carry 

RET  NC 

5/11 

RPO 

if 

parity  odd 

RET  PO 

5/11 

RPE 

If 

parity  even 

RET  PE 

5/11 

RP 

if 

sign  positive 

RET  P 

5/11 

RM 

if 

sign  negative 

RET  M 

5/11 

RO 

if 

overflow 

RET  PE 

5/11 

RNO 

if 

no  overflow 

RET  PO 

5/11 

RET  I 

return  from  interrupt 

RETl 

2 

14 

RETN 

return  from  non- 
maskable interrupt 

RETN 

2 

14 

RST  n 

(SP-1)  ^  PC/H 

RST  n 

1 

11 

(SP-2)  *■  PC/L 
PC  8  *  n 

where  0£  n<  8 


INPUT  AND  OUTPUT  GROUP 


8080 
MNEMONIC 

IN  n 

INP  r 


OPERATION 
A  ^  In 
r  ^  1(C) 


ZILOG 
MNEMONIC 

IN  A,(n) 

IN  r,(C) 


#  OF 
BYTES 

2 

2 


if  OF 

T  STATES 
11 
12 


111 


INI 

INIR 
IND 

INDR 
OUT  n 
OUTP  r 
OUTI 

OUTIR 
OUTD 

OUTDR 


(HL)  ^  1(C)  INI 
B      ^  B  -  1 

HL  HL  +  1 

repeat  INI  until  B=0  INIR 

(HL)  1(C)  IND 

B      ^  B  -  1 

HL    ^  HL  -  1 

repeat  IND  until  B=0  INDR 

On  -<-  A  OUT  (n)  ,A 

0(C)  r  OUT  (C),r 

0(C)  *-  (HL)  OUTI 

B        ^  B  -  1 

HL      ^  HL  +  1 

repeat  OUTI  until  B=0  OTIR 

0(C)  (HL)  OUTD 

B        ^  B  -  1 

HL  HL  -  1 


2 

2 

2 
2 
2 
2 

2 
2 


repeat  OUTD  until  B=0 


OTDR 


16 

16/21 
16 

16/21 
11 
12 
16 

16/21 
16 

16/21 


112 


APPENDIX  B 


A  ^  r  1  1 

<^  P  T 

00 

Ctrl 

-@ 

(NUL) 

20 

space 

@ 

60 

01 

Ctrl 

-A 

(SOH) 

2  1 

1 

k] 

A 

61 

a 

02 

Ctrl 

-  B 

(  STX) 

22 

1 1 

m 

B 

62 

b 

03 

Ctrl 

-c 

(  ETX) 

23 

# 

^43 

C 

63 

c 

0^ 

Ctrl 

-  D 

(EOT) 

2i* 

$ 

D 

Sh 

d 

05 

Ctrl 

-  E 

(  ENQ) 

25 

% 

E 

65 

e 

06 

Ctrl 

-  F 

(AC  K) 

26 

& 

i46 

F 

66 

f 

07 

Ctrl 

-G 

(BEL) 

27 

1 

47 

G 

67 

g 

08 

Ctrl 

-H 

(BS  ) 

28 

( 

i*8 

H 

68 

h 

09 

Ctrl 

-  1 

(HT  ) 

29 

) 

hS 

1 

69 

i 

0A 

Ctrl 

-J 

(  LF  ) 

2A 

J 

6A 

j 

0B 

C  t  r 

-  K 

( VT  ) 

2B 

+ 

K 

6B 

k 

0C 

Ctrl 

-  L 

(  FF  ) 

2C 

i»C 

L 

6C 

1 

0D 

Ctrl 

-M 

(CR  ) 

2D 

- 

4D 

M 

6D 

m 

0E 

Ctrl 

-  N 

(SO  ) 

2E 

4E 

N 

6E 

n 

0F 

C  t  r 

-  0 

(SI  ) 

2F 

/ 

kF 

0 

6F 

o 

10 

C  t  r 

-  P 

(OLE) 

30 

0 

50 

P 

70 

P 

1  1 

C  t  r 

-Q 

(DCl) 

31 

1 

51 

Q 

7] 

q 

1  2 

Ct  r 

-  R 

(DC2) 

32 

2 

52 

R 

72 

r 

1  3 

C  tr 

-s 

(DC3) 

33 

3 

53 

S 

73 

s 

I  k 

C  t  r 

-T 

iock) 

3^ 

5h 

T 

7k 

t 

1  5 

C  t  r 

-u 

(  NAK) 

35 

5 

55 

U 

75 

u 

1  6 

Ct  r 

-V 

(  SYN) 

36 

6 

56 

V 

76 

V 

1  7 

C  t  r 

-w 

(ETB) 

37 

7 

57 

w 

77 

w 

18 

C  t  r 

-  X 

(CAN) 

38 

8 

58 

X 

78 

X 

19 

Ctr 

-  Y 

(EM  ) 

39 

9 

59 

Y 

79 

y 

1  A 

C  tr 

-z 

(SUB) 

3A 

5A 

Z 

7A 

z 

1  B 

C  t  r 

-[ 

(ESC) 

36 

t 

58 

[ 

7B 

{ 

1  C 

C  t  r 

-\ 

(FS  ) 

3C 

< 

5C 

\ 

7C 

1 

1  D 

C  t  r 

-] 

(GS  ) 

3D 

5D 

] 

7D 

} 

1  E 

C  t  r 

(  RS  ) 

3E 

> 

5E 

7E 

\, 

I  F 

C  t  r 

(US  ) 

3F 

? 

5F 

7F 

DEL 

113 


HEX 


00 
01 
02 
03 
04 
05 
06 
07 
08 
09 
0A 
0B 
0C 
0D 
0E 
0F 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
lA 


APPENDIX  C 
8080  Disassembler 

(Including  Single  Byte  Z-80  Instructions) 


EXTENDED 
OP  CODE 


nn 


n 


N 

-2 

e 

im 


n 


-2 


MNE^^ONIC 


NOP 

LXI  B,nn 
STAX  B 
INX  B 
INR  B 
DCR  B 
MVI  B,n 
RLC 
EXAF 
DAD  B 
LDAX  B 
DCX  B 
INR  C 
DCR  C 
MVI  C,n 
RRC 

DJNZ  nn 
LXI  D,nn 
STAX  D 
INX  D 
INR  D 
DCR  D 
MVI  D,n 
RAL 

JMPR  nn 
DAD  D 
LDAX  D 


HEX 


IB 
IC 
ID 
IE 
IF 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
2A 
2B 
2C 
2D 
2E 
2F 
30 
31 
32 
33 
34 
35 


EXTENDED 
OP  CODE 


N 

-2 

e 

nn 
nn 


n 


-2 


nn 


n 

e  ^ 

nn 

nn 


MNEMONIC 


DCX  D 
INR  E 
DCR  D 
MVI  E,n 

RAR 

JRNZ  nn 
LXI  H,nn 
SHLD  nn 
INX  H 
INR  H 
DCR  H 
MVI  H,n 
DAA 

JRZ  nn 
DAD  H 
LHLD  nn 
DCX  H 
INR  L 
DCR  L 
MVI  L,n 
CMA 

JRNC  nn 
LXI  SP,nn 
STA  nn 
INX  SP 
INR  M 
DCR  M 


114 


EXTENDED 

HEX          OP    CODE  MNEMONIC 

36  n  MVI  M,n 

37  STC 
_2 

38  e  JRC  nn 

39  DAD  SP 
3A  nn              LDA  nn 
3B  DCX  SP 
3C  INR  A 
3D  DCR  A 
3E  n                MVI  A,n 
3F  CMC 

40  MOV  B,B 

41  MOV  B,C 

42  MOV  B,D 

43  MOV  B,E 

44  MOV  B,H 

45  MOV  B,L 

46  MOV  B,M 

47  MOV  B,A 

48  MOV  C,B 

49  MOV  C,C 
4A  MOV  C,D 
48  MOV  C,E 
4C  MOV  C,H 
4D  MOV  C,L 
4E  MOV  C,M 
4F  MOV  C,A 

50  MOV  D,B 

51  MOV  D,C 

52  MOV  D,D 

53  MOV  D.E 


EXTENDED 

HEX         OP    CODE  MNEMONIC 

54  MOV  D,H 

55  MOV  D,L 

56  MOV  D,M 

57  MOV  D,A 

58  MOV  E,B 

59  MOV  E,C 
5A  MOV  E,D 
SB  MOV  E,E 
5C  MOV  E,H 
5D  MOV  E,L 
5E  MOV  E,M 
5F  MOV  E,A 

60  MOV  H,B 

61  MOV  H,C 

62  MOV  H,D 

63  MOVH,E 

64  MOV  H,H 

65  MOV  H,L 

66  MOV  H,M 

67  MOV  H,A 

68  MOV  L,B 

69  MOV  L,C 
6A  MOV  L,D 
6B  MOV  L,E 
6C  MOV  L,H 
6D  MOV  L,L 
6E  MOV  L,M 
6F  MOV  L,A 

70  MOV  M,B 

71  MOV  M,C 


115 


EXTENDED 

HEX         OP    CODE  MNEMONIC 

72  MOV  M,D 

73  MOV  M,E 

74  MOV  M,H 

75  MOV  M,L 

76  HLT 

77  MOV  M,A 

78  MOV  A,B 

79  MOV  A,C 
7A  MOV  A,D 
7B  MOV  A,E 
7C  MOV  A,H 
7D  MOV  A,L 
7E  MOV  A,M 
7F  MOV  A, A 

80  ADD  B 

81  ADD  C 

82  ADD  D 

83  ADD  E 

84  ADD  H 

85  ADD  L 

86  ADD  M 

87  ADD  A 

88  ADC  B 

89  ADC  C 
8A  ADC  D 
8B  ADC  E 
8C  ADC  H 
8D  ADC  L 
8E  ADC  M 
8F  ADC  A 


EXTENDED 

HEX         OP    CODE  MNEMONIC 

90  SUB  B 

91  SUB  C 

92  SUB  D 

93  SUB  E 

94  SUB  H 

95  SUB  L 

96  SUB  M 

97  SUB  A 

98  SBB  B 

99  SBB  C 
9A  SBB  D 
9B  SBB  E 
9C  SBB  H 
9D  SBB  L 
9E  SBB  M 
9F  SBB  A 
A0  ANA  B 
Al  ANA  C 
A2  ANA  D 
A3  ANA  E 
A4  ANA  H 
A5  ANA  L 
A6  ANA  M 
A7  ANA  A 
A8  XRA  B 
A9  XRA  C 
AA  XRA  D 
AB  XRA  D 
AB  XRA  E 
AC  XRA  H 


116 


EXTENDED 
HEX         OP    CODE  MNEMONIC 


AD  XRA  L 

AE  XRA  M 

AF  XRA  A 

B0  ORA  B 

81  ORA  C 

B2  ORA  D 

B3  ORA  E 

B4  ORA  H 

B5  ORA  L 

B6  ORA  M 

B7  ORA  A 

B8  CMP  B 

B9  CMP  C 

BA  CMP  D 

BB  CMP  E 

BC  CMP  H 

BD  CMP  L 

BE  CMP  M 

BF  CMP  A 

C0  RNZ 

CI  POP  B 

C2  nn  JNZ  NN 

C3  im  JMP  nn 

C4  im  CNZ  nn 

C5  PUSH  B 

C6  n  ADI  n 

C7  RST  0 

C8  RZ 

C9  RET 

CA  im  JZ  nn 


EXTENDED 
HEX         OP    CODE  MNEMONIC 

CC  nn  CZ  nn 

CD  nn  CALL  nn 

CE  n  ACI  n 

CF  RST  1 

D0  RNC 
Dl  POP  D 

D2  nn  JNC  nn 

D3  n  OUT  n 

D4  nn  CNC  nn 

DS  PUSH  D 

D6  n  SUI  n 

D7  RST  2 

D8  RC 
D9  EXX 

DA  nn  JC  nn 

DB  LDAX  B 

DC  nn  CC  nn 

DE  n  SBB  n 

DF  RST  3 

E0  RPO 
El  POP  H 

E2  nn  JPO  nn 

E3  XTHL 

E4  nn  CPO  nn 

E5  PUSH  H 

E6  n  ANI  n 

E7  RST  4 

E8  RPE 
E9  PCHL 

EA  nn  JPE  nn 


117 


EXTENDED 

HEX  OP    CODE  MNEMONIC 

EB  XCHG 

EC  nn  CPE  nn 

EE  n  XRI  n 

EF  RST  5 

F0  RP 

Fl  POP  PSW 

F2  nn  JP  nn 

F3  DI 

F4  nn  CP  nn 

F5  PUSH  PSW 


EXTENDED 

HEX  OP    CODE  MNEMONIC 

F6  n  ORI  n 

F7  RST  6 

F8  RM 

F9  SPHL 

FA  nn  JM  nn 

FB  EI 

FC  nn  CM  nn 

FE  n  CPI  n 

FF  RST  7 


118 


APPENDIX  D 
Z-80  Extension  Disassembler 


HEX 


EXTENDED 
OP  CODE 


MNEMONIC 


HEX 


EXTENDED 
OP  CODE 


MNEMONIC 


CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 

CB 
CB 

CB 

CB 

CB 


00 
01 
02 
03 
04 
05 
06 
07 
08 
09 
0A 
0B 
0C 
0D 
0E 
0F 
10 
11 
12 
13 
14 
15 
16 
17 
18 

19 
lA 
IB 


RLC  B 
RLC  C 
RLC  D 
RLC  E 
RLC  H 
RLC  L 
RLC  (HL) 
RLC  A 
RRC  B 
RRC  C 
RRC  D 
RRC  E 
RRC  H 
RRC  L 
RRC  (HL) 
RRC  A 
RL  B 
RL  C 
RL  D 
RL  E 
RL  H 
RL  L 
RL  (HL) 
RL  A 
RR  B 
RR  C 
RR  D 
RR  E 


CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 


IC 

ID 

IE 

IF 

20 

21 

22 

23 

24 

25 

26 

27 

28 

29 

2A 

2B 

2C 

2D 

2E 

2F 

38 

39 

3A 

3B 

3C 

3D 

3E 

3F 


RR  H 
RR  L 
RR  (HL) 
RR  A 
SLA  B 
SLA  C 
SLA  D 
SLA  E 
SLA  H 
SLA  L 
SLA  (HL) 
SLA  A 
SRA  B 
SRA  C 
SRA  D 
SRA  E 
SRA  H 
SRA  L 
SRA  (HL) 
SRA  A 
SRL.B 
SRL  C 
SRL  D 
SRL  E 
SRL  H 
SRL  L 
SRL  (HL) 
SRL  A 


119 


HEX 


EXTENDED 
OP  CODE 


MNEMONIC 


HEX 


EXTENDED 
OP  CODE 


MNEMONIC 


CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 


40 
41 
42 
43 
44 
45 
46 
47 
48 
49 
4A 
4B 
4C 
4D 
4E 
4F 
50 
51 
52 
53 
54 
55 
56 
57 
58 
59 
5A 
5B 
5C 
5D 


BIT  0 


BIT  0 
BIT  0 
BIT  0 
BIT  0 
BIT  0 
BIT  0 
BIT  0 
BIT  I 
BIT  1 
BIT  1 
BIT  1 
BIT  1 
BIT  1 
BIT  1 
BIT  1 
BIT  2 
BIT  2 
BIT  2 
BIT  2 
BIT  2 
BIT  2 
BIT  2 
BIT  2 
BIT  3 
BIT  3 
BIT  3 
BIT  3 
BIT  3»H 
BIT  3,L 


B 


D 
E 
H 
L 

(HL) 
A 
B 
C 
D 
E 
H 
L 

(HL) 
A 
B 
C 
D 
E 
H 
L 

(HL) 
A 
B 
C 
D 
E 


CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 


5E 
5F 
60 
61 
62 
63 
64 
65 
66 
67 
68 
69 
6A 
6B 
6C 
6D 
6E 
6F 
70 
71 
72 
73 
74 
75 
76 
77 
78 
79 
7A 
7B 


BIT  3 
BIT  3 
BIT  4 
BIT  4 
BIT  4 
BIT  4 
BIT  4 
BIT  4 
BIT  4 
BIT  4 
BIT  5 
BIT  5 
BIT  5 
BIT  5 
BIT  5 
BIT  5 
BIT  5 
BIT  5 
BIT  6 
BIT  6 
BIT  6 
BIT  6 
BIT  6 
BIT  6 
BIT  6 
BIT  6 
BIT  7 
BIT  7 
BIT  7 
BIT  7 


(HL) 

A 

B 

C 

D 

E 

H 

L 

(HL) 

A 

B 

C 

D 

E 

H 

L 

(HL) 

A 

B 

C 

D 

E 

H 

L 

(HL) 

A 

B 

C 

D 

E 


120 


EXTENDED 
HEX        OP  CODE 


MNEMONIC 


HEX 


EXTENDED 
OP  CODE 


MNEMONIC 


CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 


7C 
7D 
7E 
7F 
80 
81 
82 
83 
84 
85 
86 
87 
88 
89 
8A 
8B 
8C 
8D 
8E 
8F 
90 
91 
92 
93 
94 
95 
96 
97 
98 
99 


BIT  7 
BIT  7 
BIT  7 
BIT  7 
RES  0 
RES  0 
RES  0 
RES  0 
RES  0 
RES  0 
RES  0 
RES  0 
RES  1 
RES  1 
RES  1 
RES  1 
RES  1 
RES  1 
RES  1 
RES  1 
RES  2 
RES  2 
RES  2 
RES  2 
RES  2 
RES  2 
RES  2 
RES  2 
RES  3 
RES  3 


H 
L 

CHL) 

A 

B 

C 

D 

E 

H 

L 

(HL) 

A 

B 

C 

D 

E 

H 

L 

(HL) 

A 

B 

C 

D 

E 

H 

L 

(HL) 
A 
B 
C 


CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 

CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 


9A 

9B 

9C 

9D 

9E 

9F 

A0 

Al 

A2 

A3 

A4 

A5 

A6 

A7 

A8 

A9 

AA 

AB 

AC 

AD 

AE 

AF 

B0 
Bl 

B2 
B3 
B4 
B5 
B6 
B7 


RES  3 
RES  3 
RES  3 
RES  3 
RES  3 
RES  3 
RES  4 
RES  4 
RES  4 
RES  4 
RES  4 
RES  4 
RES  4 
RES  4 
RES  5 
RES  5 
RES  5 
RES  5 
RES  5 
RES  5 
RES  5 
RES  5 
RES  6 
RES  6 
RES  6 
RES  6 
RES  6 
RES  6 
RES  6 
RES  6 


E 
H 
L 

(HL) 

A 

B 

C 

D 

E 

H 

L 

(HL) 

A 

B 

C 

D 

E 

H 

L 

(HL) 

A 

B 

C 

D 

E 

H 

L 

(HL) 
A 


121 


HEX 


EXTENDED 
OP  CODE 


MNEMONIC 


HEX 


EXTENDED 
OP  CODE 


MNEMONIC 


CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 

CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 


B8 

B9 

BA 

BB 

BC 

BD 

BE 

BF 

C0 

CI 

C2 

C3 

C4 

C5 

C6 

C7 

C8 

C9 

CA 

CB 

CC 

CD 

CE 

CF 

D0 

Dl 

D2 

D3 

D4 

D5 


RES  7 
RES  7 
RES  7 
RES  7 
RES  7 
RES  7 
RES  7 
RES  7 
SET  0 
SET  0 
SET  0 
SET  0 
SET  0 
SET  0 
SET  0 
SET  0 
SET  1 
SET  1 
SET  1 
SET  1 
SET  1 
SET  1 
SET  1 
SET  1 
SET  2 
SET  2 
SET  2 
SET  2 
SET  2 
SET  2 


H 
L 

(HL) 

A 

B 

C 

D 

E 

H 

L 

(HL) 

A 

B 

C 

D 

E 

H 

L 

CHL) 

A 

B 

C 

D 

E 

H 

L 


CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 

CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 
CB 


D6 
D7 
D8 
D9 
DA 
DB 
DC 
DD 
DE 
DF 

E0 
El 
E2 
E3 
E4 
E5 
E6 
E7 
E8 
E9 
EA 
EB 
EC 
ED 
EE 
EF 
F0 
Fl 
F2 
F3 


SET  2,(HL) 
SET  2, A 
SET  3,B 
SET  3,C 
SET  3,D 
SET  3,E 
SET  3,H 
SET  3,L 
SET  3,(HL) 
SET  3, A 
SET  4,B 
SET  4,C 
SET  4,D 
SET  4,E 
SET  4,H 
SET  4,L 
SET  4,(HL) 
SET  4, A 
SET  5,B 
SET  5,C 
SET  5,D 
SET  5,E 
SET  5,H 
SET  5,L 
SET  5,(HL) 
SET  5, A 
SET  6,B 
SET  6,C 
SET  6,D 
SET  6,E 


122 


EXTENDED  EXTENDED 


HEX 

OP  CODE 

MNEMONIC 

HEX 

OP 

CODE 

MNEMONIC 

CB 

F4 

SET  6,H 

DD 

70 

d 

LD  (IX+d)  ,B 

CB 

F5 

SET  6,L 

UD 

71 

d 

LU  (IX+d),C 

CB 

F6 

SET  6,(HL) 

DD 

72 

d 

LD  (IX+d) ,D 

CB 

F7 

SET  6, A 

DD 

73 

d 

LD  (IX+d),E 

CB 

F8 

SET  7,B 

DD 

74 

d 

LD  (IX+d)  ,H 

CB 

F9 

SET  7,C 

DD 

75 

d 

LD  (IX+d),L 

CB 

FA 

SET  7,D 

DD 

77 

d 

LD  (IX+d), A 

CB 

FB 

SET  7,E 

DD 

7n 

d 

LD  A.(IX*d) 

CB 

FC 

SET  7,H 

DD 

36 

d 

ADD  A, (IX+d) 

CB 

FD 

SET  7,L 

DD 

3E 

d 

ADC  A, (IX+d) 

CB 

FE 

SET  7,(HL) 

DD 

96 

d 

SUB  (IX+d) 

CB 

FF 

SET  7, A 

DD 

9E 

d 

SBC  A, (IX+d) 

DD 

09 

DAD  IX, BC 

DD 

A6 

d 

AND  (IX+d) 

DD 

IQ 

DAD  IX, DE 

DD 

AH 

d 

XOR  (IX+d) 

DD 

21  nn 

LD  IX, nn 

DD 

B6 

d 

OR  (IX+d) 

DD 

22  nn 

LD  (nn),IX 

DD 

BH 

d 

CP  (IX+d) 

DD 

23 

INC  IX 

DD 

CB 

d  06 

RLC  (IX+d) 

DD 

29 

DAD  IX, IX 

DD 

CB 

d  0E 

RRC  (IX+d) 

DD 

2A  nn 

LD  IX, (nn) 

DD 

CB 

d  16 

RL  (IX+d) 

DD 

2B 

DEC  IX 

DD 

CB 

d  IP. 

RR  (IX+d) 

DD 

34  d 

INC  (IX+d) 

DD 

CB 

d  26 

SLA  (IX+.l) 

DD 

35  d 

DEC  (IX+d) 

DD 

CB 

d  2r; 

SRA  (IX+d) 

DD 

36  d  n 

LD  (IX+d),n 

DD 

CB 

d  3E 

SRLR  (IX+d) 

DD 

39 

DAD  IX, SP 

DD 

CB 

d  46 

BIT  0,(IX+d) 

DD 

46  d 

LD  B,(IX+d) 

DD 

CB 

d  4E 

BIT  l,(IX+d) 

DD 

4E  d 

LD  C,(IX+d) 

DD 

CB 

d  56 

BIT  2, (IX+d) 

DD 

56  d 

LD  D,(IX+d) 

DD 

CB 

d  5E 

BIT  3, (IX+d) 

DD 

5E  d 

LD  E,(IX+d) 

DD 

CB 

d  66 

BIT  4, (IX+d) 

DD 

66  d 

LD  M,(IXt-d) 

DD 

CB 

d  6E 

BIT  5, (IX+d) 

DD 

6E  d 

LD  L,(IX+d) 

DD 

CB 

d  76 

BIT  6, (IX+d) 

123 


ntA 

EXTENDED 
Ur  LUUt 

MNEMONIC 

HFY 
riEA 

EXTENDED 
np  mnF 

Ur  V^UUE 

MINeMUN  IL. 

nn 

PR  A  7F 

RTT 
DX  1 

Fn 

HU 

RFTT 

tvC  i  X 

nn 
uu 

PR  H  SA 

DFQ 

JO,  ^iA+Q } 

pn 

EU 

AT! 

I  n  D  A 

LiU    K,  A 

nn 
uu 

PR  A  SP 

RF<? 

icno 

1  f  \  i  A^Cl  J 

pn 

EU 

QRP  nP 
ODV^  UE 

nn 

uu 

PR  H  (if, 

UPt; 

KED 

9  fTY^-A^ 
i.  f  ^iA+U ) 

Fn 

OO  lUl 

I n   Tnnl  np 

LlU        ^IIJI )    y  UC 

nn 
uu 

PR  1-1  QF 

J  f  \ 1 A^a  J 

pn 

EU 

';7 

O  1 

T  n   A  T 
IjU  Ay  X 

nn 
uu 

PR   rl    A  A 

DFQ 

H  ,  ^^  1 A+U  ) 

Fn 
cu 

A 

On. 

Anp  HI  np 

nn 
uu 

PR  A  AF 

RF<; 

D  P  ^ 1 ATQ  J 

pn 
cu 

CD  nn 
Ou  lUl 

I  n   np  fnn"\ 
ijU    UC  ,  ^iUL ) 

nn 
uu 

PR  A  RA 

Li  D    CI  DO 

RFQ 

O ,  ^ 1 Atq  j 

pn 
cu 

i^F 
Or 

I  n  A  R 

LlU   /\,  I\ 

nn 
uu 

PR   A  RF 
V^D  a  DC 

7  fTX+fil 

pn 

cu 

A? 

CRP    HI  HI 
o  Dv>  nij ,  nij 

nn 

uu 

PR   H  Pfi 

Fn 

67 

RRD 

nn 
uu 

PR  f1  PF 

OC  1 

i ,  ^ 1 A+Q  J 

ED 

6A 

ADC  HL  HL 

nn 
uu 

PR  A  nA 
UD   Q  UO 

CPT 

z  y  ^ 1 A+a  J 

Fn 

6F 

RLD 

nn 
uu 

PR  <^  nF 

OC  1 

J  f  [_1  A+U  J 

Fn 

cu 

77 

C  RP    U  T  CD 

nn 
uu 

PR    r1  FA 

L>o  Q  no 

QFT 
oC  1 

t ,  ^ 1 AtQ  j 

Fn 

7'^  nn 

I  n  Cnn"> 

LlU  ^_nn  J  ,  Or 

nn 
uu 

PR   A  FF 

<?FT 
OC  1 

0,^1  A*C1  J 

Fn 

cu 

7A 

Anp  HI  QP 

AULi  riLiyOr 

nn 

PR  fl  FA 

OC  1 

O  ,    1  A*C1  J 

Fn 

7R 

I  n  Tnn"! 

LiLf    Or  ,  ^1111 J 

nn 

uu 

PR   A  FF 
LiD    CL    r  c 

QFT 
OE 1 

/  f  \^  i  A+Q ) 

pn 

cu 

A^ 

I  ni 

LlUX 

nn 
uu 

PI 

El 

POP 

IX 

pn 

EU 

A1 

PPT 
L>r  X 

nn 
uu 

EJ 

EX 

(SP),IX 

Fn 
nu 

AS 

I  nn 

LiUU 

nn 

uu 

PUSH  IX 

pn 

cu 

AQ 

H  J 

ppn 

or  U 

• 

nn 
uu 

PQ 

E7 

JP 

(IX) 

pn 

EU 

Rd 

T  nx D 

LiUXK 

nn 
uu 

PQ 

LD  SP,IX 

pn 

EU 

Dl 

PDTD 
C^r  XK 

pn 
cu 

SBC 

HL,BC 

pn 

EU 

R8 
Do 

I  nnR 

LiUUK 

pn 

cu 

to  1111 

LD 

(nn) ,BC 

pn 
cu 

RQ 

Dy 

ppnR 

V-ir  UK 

pn 

11 

NEC 

pn 

ID 

RETN 

cn 
ru 

See  DD  instruction. 

pn 

EU 

A7 
1  / 

LD  " 

[,A 

Substitute 

"Y"  for  every 

ED 

4A 

ADC 

HL,BC 

"X"  -  e.g. 

ADD  IX, IX 

ED 

4B  nn 

LD  BC,(nn) 

becomes  ADD  IY,IY 

124 


ANSWERS  TO  EXERCISES 


BITS,  BYTES  AND  BOOLEAN  OPERATORS 


la)  101 


I 

+  0 
+  I 


X 
X 
X 


2' 

2' 


=  I 
0 

+  4 


b) 

1  101 

1 

X 

2^ 

=  1 

+  0 

X 

2' 

0 

+  1 

X 

2^ 

4 

+  1 

X 

2^ 

+  8 
13 

f)  II00I0I0 


0 

X 

2^ 

=  0 

+ 

1 

X 

2' 

2 

+ 

0 

X 

2^ 

0 

+ 

1 

X 

2^ 

8 

+ 

0 

X 

2^ 

0 

+ 

0 

X 

2^ 

0 

+ 

1 

X 

2^ 

64 

+ 

1 

X 

2^ 

+  128 
202 

c)  III0I 


d)  I0I0II 


e)  10000000 


1 

X 

2^  - 

1 

+ 

0 

X 

2' 

0 

+ 

1 

X 

22 

4 

g) 

1 000 1 II 0 

= 

0 

X 

2^ 

+ 

1 

X 

2^ 

8 

+ 

1 

X 

2' 

+ 

1 

X 

2^  + 

16 

+ 

1 

X 

29 

+ 

1 

X 

2^ 

+ 

0 

X 

2^ 

1 

X 

2^  = 

1 

+ 

0 

X 

2^ 

+ 

1 

X 

2' 

2 

+ 

0 

X 

2^ 

+ 

0 

X 

2^ 

0 

+ 

1 

X 

2^ 

+ 

1 

X 

2^ 

8 

+ 

0 

X 

2^ 

0 

+ 

1 

X 

2^  + 

32 

43 

0 

X  2^ 

=  0 

h) 

1 1 1 1 1001 

1 

X 

2«' 

+ 

0 

X  2' 

0 

+ 

0 

X 

2' 

+ 

0 

2 

X  2 

0 

+ 

0 

X 

2^ 

+ 

0 

X  2^ 

0 

+ 

X 

2^ 

+ 

0 

4 

X  2 

0 

+ 

X 

2' 

+ 

0 

5 

X  2^ 

0 

+ 

X 

2^ 

+ 

0 

X  2^ 

0 

+ 

X 

2^ 

+ 

1 

X  2^ 

+  128 

+ 

X 

2^ 

2 
4 
8 
0 
0 
0 


142 


128 


=  I 
0 
0 
8 
16 
32 
64 
+  128 
249 


125 


)  00010010 


j)     01  I  1001  I 


:  0 

X 

=  0 

k) 

1 1 1000100 

= 

0 

X 

2^ 

=  0 

+  1 

X 

2' 

2 

+ 

0 

X 

2' 

0 

+  0 

X 

2^ 

0 

+ 

1 

X 

2^ 

4 

+  0 

X 

2^ 

0 

+ 

0 

X 

2^ 

0 

+  1 

X 

2^ 

16 

+ 

0 

X 

2^ 

0 

+  0 

X 

2^ 

0 

+ 

0 

X 

2^ 

0 

+  0 

X 

2^ 

0 

+ 

1 

X 

2^ 

64 

+  0 

X 

2^ 

+  0 

+ 

1 

X 

2^ 

128 

1 0 
1 0 

1 
1 

Y 
A 

2^ 

tZUO 

452 

1 ) 

I0I0I0I0I 1 

= 

1 

X 

2^ 

=  1 

2^ 

+ 

1 

X 

2' 

2 

=  1 

X 

=  1 

+ 

0 

X 

2^ 

0 

+  1 

X 

2' 

2 

+ 

1 

X 

2^ 

8 

+  0 

X 

2^ 

0 

+ 

0 

X 

2^ 

0 

+  0 

X 

2^ 

0 

+ 

1 

X 

2^ 

32 

+  1 

X 

2^ 

16 

+ 

0 

X 

2^ 

0 

+  1 

X 

2^ 

32 

+ 

1 

X 

2^ 

128 

+  1 

X 

2^ 

64 

+ 

0 

X 

0 

+  0 

X 

2"^ 

+  0 

+ 

1 

X 

2' 

+512 

I  15 


683 


2a)    6p    =    6^    =  0II0B 


b)     14^    =  =  Ill0g 


c)  127. 


7  r  15    =    7F,,    =    01  I  I  I  I  I  I 


16  JJTJ 


H 


B 


d)  280, 


256  ^28^ 


r  24    =     I  18^    =    00010001 I000„ 
n  D 


e)  542. 


256  1342 


2  r  30    =    2 IE,,    =    00100001  1110 


"H 


B 


I  r  14 


16  J5^ 


f)     1077^    =   4  r  53    =    435^    =  0I0000II0I0I 

°     256  jrm  ^ 

3  r  5 
\6j55 


126 


g)    4095      =   15  r  255    =    FFF^    =  llllllllllll 

.  256  ^  ^ 


 l_5  r  15 

16  y255 


h)    8702      =   2  r  510    =  2IFE^ 

^         4096  ;  8702  " 

 I   r  254    =    00 1 0000 1  I  I  I  I  I  I  I  0 

256  75l¥ 

 l_5  r  14 

16  J254 


i)     15,430      =   3  r  3142    =  3C46 

^         4096  ) 15430 

 l_2  r  70       =    001  I  I  1000 1  0001  10 

256  )3I42 

4  r  6 
16  J7^ 


j)     43,751      =   l_0  r  2791     =  AAE7 

°         4096  43751 

 [0  r  231      =     I0I0I0I0I I  1001  I  I 

256  2791 

 I4_  r  7 

16  231 


k)    65,552      =   l_  r  16    =  10010 

^         65536  65552 

 0  r  16    =  00010000000000010000 

4096  16 

 0  r  16 

256  16 

 l_  r  0 

16  16 


127 


I)    70,980     =  I  r  5444  =  11544 

^         65536  70980 

 I_rl348  =  000I000I0I0I0I000I00 

4096  5444 

 5  r  68 

256  1348 

 4  r  4 

16  68 


3a)    000001 11=    7  I  I  I  I  1 000 

+  I 

I  I  I  I  1001  =  -7 


b)  00010001  =  17         I  I  101  I  10 

+  I 

I  I  101  I  I  I  =  -17 

c)  000101  I  I  =  23         I  I  101000 

+  I 

I  I  101 001  =  -23 


d)    001 10000  =  48         I  1001  I  I  I 

+  I 

I  1010000  =  -48 


e)  01 101000  =  104        100101  I  I 

+  I 

1001 1000  =  -104 

f )  01  I  I  I  I  I  I  =  127  10000000 

+  I 

10000001  =  -127 

4a)     00001001  =  9 


128 


b)    0001 1001  =  25 


c)     IIIII0II  00000100 

+  I 

tmm\t\  =  5,  so  1 1 1 1 101 1  =  -5 


d)    001001  I  I  =    27^    =  39 

n 


e)     II  I  10010  00001 101 

+  I 


00001 110    =     14,     so     I  I II00I0  =  -14 


f)     II0I0000  00I0IIII 

+  I 

00110000    =    30^,  =    48,    so    1101 0000  =  -48 


5a)    000010! 1=11       No  Carry 
+  00001  I  I  I         -t-  15       No  Overflow 
000 II 0 1 0  26 


b)    00010001      =      17       No  Carry 
-^  I  I  I0I0I  I        -K-2I  )      No  Overflow 
I  I  I  I  I  I  00  -4 


c)    00101  I  10 
-  00001 100 
00 1 000 1 0 


46 
12 
34 


No  Carry 
No  Overflow 


^   d)    01 101000    ^      104       No  Carry 
+  001 1011  I         +  55  Overflow 
I00IIIII  159 


129 


e)    101 1 1  101         -  67 
-  01 I0I0I I  -107 
01 01 0010  -174 


No  Carry 
Overf low 


f )     101  I  I  101         -  67  Carry 

+  01  I0I0I  I  -1-107  No  Overflow 
I  00101000  40 


6a)    AND  OR   XOR 

00000000  II0I0I0I  II0I0I0I 

Carry=  0                       C=  0  C=  0 

Zero  =1                        Z=  0  Z=  0 

Sign  =  0                       S=  I  S=  I 

Parity=l                       P=  0  P=  0 

b)    I0II0I00  llllllll  0I00I0II 

C=  0                          C=  0  C=  0 

Z=  0                          Z=  0  Z=  0 

S=  I                           S=  I  S=  0 

P=  I                           P=  I  P=  I 

C)       AND  OR   XOR 

OOOIOIIO  llllllll  IllOIOOl 

C=  0                       C=  0  C=  0 

Z=  0                       Z=  0  Z=  0 

S=  0                       S=  I  S=  I 

P=  0                        P=  I  P=  0 

d)  I0I000I0  IIII0III  0I0I0I0I 

C=  0                       C=  0  C=  0 

Z=  0                       Z=  0  Z=  0 

S=  I                        S=  I  S=  0 

P=  0                        P=  0  P=  I 

e)  00010000  1001  1 101  10001 101 

C=  0                       C=  0  C=  0 

Z=  0                       Z=  0  Z=  0 

S=  0                       S=  I  S=  I 

P=  0                       P=  0  P=  1 


130 


f )  00000000  I t I  1 000 1  I  1 1  1 000 1 

C=  0                       C=  0  C=  0 

Z=  I                        Z=  0  Z=  0 

S=  0                       S=  I  S=  I 

P=  I                        P=  0  P=  0 

g)  00000000  III  Mill  llllllll 

C=  0                        C=  0  C=  0 

Z=  I                        Z=  0  Z=  0 

S=  0                       S=  I  S=  I 

P=  I                        P=  I  P=  I 

h)  II 0011 II  II00IIII  00000000 

C=  0                       C=  0  C=  0 

Z=  0                       Z=  0  Z=  I 

S=  I                        S=  I  S=  0 

P=  I                        P=  I  P=  I 


WHERE  IS  MY  VARIABLE? 


I )  3080 


MOV  A,D 
MOV  D,E 
MOV  E,A 


Z-80 

LO  A,D 
LD  D,E 
LD  E,A 


the  point  is  that  an 
Intermediate  storage 
area  must  be  use<j 


2 )     II  I  1 0 1 00 


3)    After  the  first  instruction  HL  contains: 

2039,  so  HL  now  points  to  a  new  location. 

After  the  second  instruction    A  contains: 
00 


4)  3AF334 


131 


5)     Interprets  the  contents  of  index  register. IX  as  an  address.  Takes 
that  address  plus  12  and  loads  the  contents  of  the  byte  into 
register  E. 


6)    The  first  loads  the  value  of  the  two  bytes  beginning  at  SPOT  into 
register  pair  HL.    The  second  loads  the  address  of  SPOT  into 
register  pair  HL. 


7)    AF  4020L,.      The  registers  are  swapped. 

n 


8)  No, 


9)  a)  LXI 
LO 


SP,6F32H  (8080) 
SP,6F32H  (Z-80) 


NOTE:    Assemblers  differ  on  the  form 
Hex  numbers  must  be  written  in.  The 
assembler  will  put  it  in  swapped  format 
within  the  Instruction. 


9)    b)  BC  =  0302 
SP  =  6F34 


10)    Here  is  a  blow-by-blow  account  of  the  effects: 

a)  Register    A    contains  the  value  3. 

b)  Memory  location  2400  contains  the  value  3, 

c)  Index  register  IX  contains,  after  unswapping,  2403|^, 

d )  Reg  i  ster    C    conta  i  ns  the  va I ue  21. 


A  METHOD  TO  OUR  LOGIC 


I  )  8080 

SUB  A 

ADD  M 

INX  H 

ADD  M 

INX  H 

ADD  M 


Z-80 

SUB  A 

ADD  A,(HL) 

INC  HL 

ADD  A 

INC  HL 

ADD  A, (HL) 


132 


2)     MOV  A,C 

ADD  L 

MOV  L,A 

MOV  A,B 

ADC  H 

MOV  H,A 


LF  A,C 

ADD  A,L 

LD  L,A 

LD  A,B 

ADC  A,H 

LD  H,A 


3)    Desired  bit  pattern:     I  III  1010    =  FA| 
CPI      FAH  CP  FAH 

The  zero  flag  will  be  set  on  a  match. 


4)    Signed    V    XORS  =  I 
Unsigned    C  =  I 


5)    a)     Load  into  the  accumulator  the  high  order  byte  of  RIGA 

b)  Load  into  the  HL  pair  the  address  of  the  high  order  byte  of  BIGB 

c)  Compare  the  high  order  bytes.     If  they  are  not  equal  we  are  done. 
We  have  our  answer  in  the  sign  and  overflow  flags. 

d)  if  the  high  order  bytes  were  equal,  repeat  comparison  on  low  order 
bytes. 


6)    To  perform    HL  HL 

8080 

MOV  A,L 
SUB  C 
MOV  L,A 
MOV  A,H 
SBB  B 
MOV  H,A 


-  BC: 

Z-80 

LD  A,L 

SUB  C 

LD  L,A 

LD  A,H 

SBC  A,B 

LD  H,A 


JUMPS,  LOOPS  AND  MODULAR  PROGRAMING 


I )    For  unsigned  numbers 

8080  Z-80 

a)  JC      SPOT  JP  CSPOT 

b)  JC      SPOT  JP  C,SPOT 
JZ      SPOT                          JP  Z,SPOT 


133 


By  using  these  two  jumps 

one  after 

the 

other. 

the  =  case  are 

hand  1 ed . 

c) 

JZ 

SPOT 

JP 

Z,SPOT 

d) 

JNZ 

SPOT 

JP 

NZ,SPOT 

e) 

JNC 

SPOT 

JP 

NC,SPOT 

f ) 

JC 

SKI  P 

JR 

C,SKIP 

JZ 

SKIP 

JR 

Z,SKIP 

J  MP 

SPOT 

JP 

SPOT 

SKIP: 

• 
• 
• 

SKIP: 

• 
• 
• 

The  method  used  here  is  to  avoid  jumping  to  SPOT  if  VARA  <  VARB. 
Other  techniques  are  possible  as  well. 


2)    For  signed  numbers.     In  several   instances  here,  we  will  want  the 
the  effect  of  (V  XOR  S),  but  there  is  no  single  instruction  that 
will  exclusive  or  flags  for  us.    The  following  flow  chart  will 
outline  the  test  we  must  make: 


N 

/ 

V    XOR  S 

0 

We  will  use  the  carry  flag  to  hold  the  result  of  (V  XOR  S). 
8080  Z-80 


B: 


STC 

JO 

CMC 

JP 

CMC 

NOP 


B 


(Set  the  carry) 

(Jump  if  V  =  1) 

(Now  C  =  V) 

(Jump  if  S  =  0) 

(Now  C  =  V  XOR  S) 

(Do  nothing  used  so 
B  can  be  a  label  on 
an  instruction.) 


SCF 
JP  PE,A 

CCF 
A:     JP  P,B 

CCF 
B:  NOP 


134 


At  the  conclusion  of  this  little  sequence  of  code,  the  carry  flag 
can  be  used  just  as  it  was  used  in  unsigned  numbers.     Let's  name 
the  above  sequence  VXORS.     (If  your  assembler  has  macro  capability, 
look  into  how  you  could  create  a  macro  named  VXORS  to  perform  the 
above  sequence. ) 


Now  the  answer  to  this  exercise  can  be  given.  Everywhere  VXORS  is 
used,   it  means  the  above  five  instructions. 


8080 

Z-80 

a) 

VXORS 

VXORS 

JC 

SPOT 

JP 

C,SPOT 

b) 

VXORS 

VXORS 

JC 

SPOT 

JP 

C,SPOT 

JZ 

SPOT 

JP 

Z,SPOT 

c) 

JZ 

SPOT 

JP 

Z,SPOT 

d) 

JNZ 

SPOT 

JP 

NZ,SPOT 

e) 

VXORS 

VXORS 

JNC 

SPOT 

JP 

NC,SPOT 

f ) 

VXORS 

VXORS 

JC 

SKIP 

JR 

C,SKiP 

JZ 

SKIP 

JR 

Z,SKIP 

J  MP 

SPOT 

JP 

SPOT 

SKIP:     .  SKIP: 


Except  for  the  addition  of  VXORS,  these  are  identical  to  the  answers 
to  exerc  i  se  # I . 

3)     Inputs:    ARYADR    -  start  address  of  the  array 

SIZE       -  number  of  elements 

Outputs:  REGISTER  A  -    Sum  ( I f  no  overflow) 

OVFLAG  -    set  to  a  value  of  1  if  overflow 

 8080  

SUM:  PUSH       B  Save  BC  register  pair 

PUSH       H  Save  HL  register  pair 

LHLD       ARYADR  Fetch  start  address  of  the  array 


135 


LOOP: 


OK: 


DONE: 


SUB 
STA 
LDA 
ANA 

JZ 

MOV 

SUB 

ADD 

J  NO 

MVI 

STA 

J  MP 

I  NX 

OCR 

JNZ 

POP 

POP 

RET 


A 

OVFLAG 

SIZE 

A 

DONE 

B,A 
A 

M 

OK 
A,  I 

OVFLAG 
DONE 
H 
B 

LOOP 

H 

8 


Zero  the  accumulator 

Clear  overflow  flag 

Fetch  the  number  of  elements 

Checks  to  see  If  there  are  zero  elements  in 
the  array  without  changing  the  value  in  A 

If  there  are  none,  we're  done.    The  sum  is 
correctly  reported  as  zero 

Otherwise,  move  the  size  to  register  B 

Zero  the  sum 

Add  array  va I ue 

Jump  if  no  overflow  occurred 

Otherwise    A  -<-  I 

Set  the  overflow  flag 

Done 

Next  e I ement 
Decrement  count 
Repeat  unt i I  done 
Restore  HL  pair 
Restore  BC  pa  i  r 


Z-80 


SUM: 


LOOP: 


OK: 
DONE: 


PUSH  BC 

PUSH  HL 

LD  HL, (ARYADR) 

SUB  A 

LD  (OVFLAG), A 

LD  A, (SIZE) 

AND  A 

JR  Z,DONE 

LD  B,A 

SUB  A 

ADD  A,(HL) 

JP  PO,OK 

LD  A,  I 

LD  (OVFLAG), A 

JR  DONE 

INC  HL 

DJNZ  LOOP 

POP  HL 

POP  BC 

RET 


Save  BC  register  pair 

Save  HL  register  pair 

Fetch  start  address  of  the  array 

Zero  the  accumulator 

Clear  the  overflow  flag 

Fetch  the  number  of  elements 

Checks  to  see  if  there  are  zero  elements  in 
the  array  without  changing  the  value  in  A 

If  there  are  none,  we're  done.    The  sum  is 
correctly  reported  as  zero 

Otherwise,  move  the  size  to  register  B 

Zero  the  sum 

Add  array  va I ue 

Jump  If  no  overflow  occurred 

Otherwise  A  ^  I 

Set  the  overflow  flag 

Done 

Next  element 
Decrement  count 
Restore  HL  pa  i  r 
Restore  BC  pair 


136 


4)    Other  methods  are  possible,  but  this  one  first  compares  high  order 
bytes,  if  equal,  then  low  order  bytes. 


8080 

7. 

LHLD 

BIGB 

(Fetch  BIGB) 

LD 

LDA 

BIGA+1 

(Fetch  high  order  byte  of  BIGA) 

LD 

CMP 

H 

(Compare  high  order) 

CP 

JZ 

CKLOW 

(If  equal,  check  low) 

JR 

JC 

CALB 

(A  conditional  call  won't  work 

JR 

J  MP 

CALA 

here.  Why?) 

JR 

CKLOW: 

LDA 

BIGA 

(Fetch  low  order  byte  of  BIGA) 

CKLOW: 

LD 

CMP 

L 

(Compare  low  order) 

CP 

JNC 

CALA 

(Jump  if  BIGA  larger) 

JR 

CALB: 

CALL 

BBIGR 

CALB: 

CALL 

JMP 

DONE 

(To  avoid  calling  ABIGR  upon 
return  from  BBIGR) 

JP 

CALA: 

CALL 

ABIGR 

CALA: 

CALL 

DONE: 

DONE: 

Z-80 


5)    Simply  insert  "VXORS"  right  after  the  "Compare  High  Order." 
Why  is  it  not  needed  after  the  "Compare  Low  Order"? 


6)    Continued  on  next  page. 


8080 


Z-80 


LDA  COUNT  (Fetch  #  of  clients;  this  time  we 

wi I  I  assume  that  count  ^  0) 

MOV  B,A  (Save  in  register  B) 

LXI  H, PEOPLE  (Start  address  of  the  array) 

LXI  D,3  (Increment  for  the  address) 

MVI  A,0FAH  (FAl,  is  the  desired  descriptor  byte) 

n 

LOOP:  CMP  M  (Compare  to  person  in  Array)  L(X)P: 

JZ  MATCH  (Jump  if  match  found) 

DAD  D  (Increment  to  next  person) 

DCR  B  (Repeat  until  Match  or  Done) 

JNZ  LOOP 

CALL  NOSUCH  (No  match  found) 


LD       A, (COUNT) 


LD 

LD 

LD 

LD 

CP 

JR 

ADD 

DJNZ 


B,A 

HL, PEOPLE 

DE.3 

A,0FAH 

(HL) 

Z, MATCH 

HL,DE 

LOOP 


CALL  NOSUCH 


MATCH:  I NX 
MOV 


H 

E,M 


(To  point  to  jump  address) 
(Fetch  low  order  byte) 


MATCH:  INC  HL 

LD  E,,(HL) 


137 


INX  H  (To  point  to  high  order)  INC  HL 

MOV  D,M  (Fetch  high  order  byte)  LD  D,(HL) 

XCHG  (Jump  address  in  HL)  EX  DE,HL 

PCHL  (Jump)  JP  (HL) 


Match  could  be  included  inside  the  loop  by  changing  the  jump  on  zero  to 
a  jump  on  non-zero  and  skipping  around  this  piece  of  code.    The  only 
reason  it's  not  done  that  way  here  is  to  clearly  separate  the  two 
prob I  ems: 

a)  looping  through  PEOPLE  looking  for  a  match,  and 

b)  transferring  to  the  jump  address,  when  a  match  is  found, 

NOTE:  A  structure  such  as  PEOPLE  which  contains  jump  addresses  is  often 
called  a  vector  table.  The  jump  address  itself  is  usually  called 
a  vector. 


BIT  FIDDLING  AND  MESSAGE  MAKING 

I)     Input:        MLTPLR       two  eight  bit  positive  numbers 
MLTCND 

Output:      PRODCT       a  two  byte  product  of  the  two  inputs 

The  8080  version  of  this  subroutine  and  its  Z-80  counterpart  will 
differ  significantly  owing  to  the  ability  of  the  Z-80  to  rotate 
and  shift  any  desired  register,    The  two  routines  will  therefore 
be  presented  separately. 


8080 

Mu 1 1 i  p 1 y 

Subrout i  ne 

PUSH 

PSW 

SAVE  REGISTERS 

PUSH 

B 

PUSH 

D 

LDA 

MLTPLR 

Fetch  mu 1 1  i  p 1 i  er 

MOV 

E,A 

Save  in  low  order  byte  of  DE  pair 

LDA 

MLTCND 

Fetch  multipl icand 

MOV 

C,A 

Save  in  register  C, 

MVI 

B,8 

Load  the  loop  counter  in  B. 

tm 

D,0 

Zero  high  order  byte  of  DE  pair 

138 


LOOP:  MOV  A,E  To  check  bit  0  of  the  multiplier 

RRC  Shift  bit  0  into  carry 

JNC  NOADD  If  it  is  zero,  skip  the  addition 

MOV  A,D  if  set,  add  the  multiplicand  to  the 

ADD  C  order  byte 

MOV  D,A  Replace  the  result 

NOADD:         MOV  A,D  The  apparent  redundancy  is  due  to  the  case 

where  the  original  move  to  A  from  D  was 
ski  pped 

ANA  A  Clear  carry 

RAR  Shift  high  order  byte 

MOV  D,A  Replace  the  result 

MOV  A,E  Fetch  low  order  byte 

RAR  Shift  low  order  byte  bringing  in  bit  0 

of  the  high  order  byte 

MOV  E,A  Replace  low  order  byte 

DCR  B  Loop  increment 

JNZ  LOOP  Repeat  unti I  done 

XCHG  Swap  DE  and  HL 

SHLD  PRODCT  The  result  was  in  the  DE  pair 

XCHG  Swap  back 

POP  D 

POP  B 

POP  PSW 

RET  Done 

 Z-80  Multiply  Subrout  i  ne  

MLTPLY:        PUSH  AF  Save  registers 

PUSH  BC 

PUSH  DE 

ID  A,(MLTPLR)  Fetch  mu I t i p I ier 

LD  E,A  Save  in  low  order  byte  of  DE  pair 

LD  A,(MLTCND)  Fetch  mu  It ip I icand 

LD  C,A  Save  in  register  C 

LD  B, 8  Load  the  loop  counter  in  B 

SUB  A  Clear  the  A  register.  Registers  A  and  E 

will  be  used  as  a  pair  during  formation 
of  the  product 

LOOP:  BIT  0,E  Check  bit  0  of  the  multiplier 

JR  Z, NOADD  If  it  is  zero,  skip  the  addition 


139 


NOADD : 


ADD 

SRL 
RR 

DJNZ 
LD 

LD 


A,C 

A 
E 

LOOP 
D,A 


If  set,  add  the  multiplicand  to  the  high 
order  byte 

Shift  the  high  order  byte  right 

Shift  the  low  order  byte  bringing  in  bit 
0  of  the  high  order  byte 

Repeat  unt  i I  done 

Place  high  order  byte  of  product  into  high 
order  byte  of  DE  pair 


(PRODCT),DE  Store  result 


POP 
POP 
POP 
RET 


DE 
BC 
AF 


Restore  registers 


Done 


2)     Inputs:       MLTPLR       Two  eight  bit  numbers  not  necessarily  positive 
MLTCND 

PRODCT       A  two  byte  product  of  the  two  inputs 


808IZ) 


Comments 


Z-80 


MULT2:  PUSH 
PUSH 
PUSH 
MVI 

LDA 
MOV 
ANA 
JP 

CMA 
INR 
INR 

POS  1:  STA 

LDA 
MOV 
ANA 
JP 

CMA 
INR 


PSW 

H 

D 

H,0 

MLTPLR 

E,A 

A 

POS  1 


A 
H 

MLTPLR 

MLTCND 
D,A 

A 

POS  2 


Save  registers  MULT2: 


PUSH  AF 
PUSH  BC 
PUSH  DE 

Clear  sign  of  LD  B,0 
result  flag 

Fetch  first  operand  LD       A, (MLTPLR) 

Save  in    E  LD  E,A 

Test  sign  of  number  AND  A 

Skip  complement  if  JP       P,POS  1 
positive 

Form  2's  complement  if  NEG 
negative 

Increment  sign  of  result  INC  B 
flag 

Replace  positive  POS  1:  LD  (MLTPLR), A 
mu 1 1  i  p I i  er 

Fetch  second  operand  LD       A, (MLTCND) 

Save  in    D  LD  D,A 

Test  sign  of  number  AND  A 

Skip  complement  if  JP       P,POS  2 
positive 

Form  2 ' s  comp 1 ement  i  f  NEG 
negative 


140 


INR 

POS  2:  STA 

CALL 

MOV 

RAR 

JNC 

LHLD 

MOV 

CMA 

MOV 

MOV 

CMA 

MOV 

INX 

SHLD 

RESPOS:  MOV 
STA 
MOV 

STA 

POP 

POP 

POP 

RET 


H 

MLTCND 

MLTPLY 
A,H 

RESPOS 

PRODCT 
A,H 

H,A 
A,L 

L,A 

H 

PRODCT 
A,E 

MLTPLR 
A,D 

MLTCND 

D 

H 

PSW 


Increment  sign  of  result 
flag 


Replace  positive  POS  2; 
multipl icand 

Get  positive  result  in 

product 

Test  bit  0  of  sign  of 
result  flag 

If  the  bit  is  0  the  result 
is  positive.  Otherwise 
complement  the  result 

Fetch  the  result 

Form  1 ' s  comp I ement 

of  each  byte 


INC 
LD 

CALL 
BIT 


Increment  register  pair 
for  2's  complement 

Store  the  properly  signed 
result 


LD 

LD 

CPL 

LD 

LD 

CPL 

LD 

INC 

LD 


Restore  initial 
signed  inputs  in 
MLTPLR  and  MLTCND 


Restore  registers 


Done 


RESPOS:  LD 
LD 
LD 

LD 

POP 

POP 

POP 

RET 


(MLTCND), A 

MLTPLY 
0,B 


JR       Z, RESPOS 


BC, (PRODCT) 
A,B 

8, A 
A,C 

C,A 

BC 

( PRODCT ),BC 
A.E 

(MLTPLR), A 
A,D 

(MLTCND), A 

DE 

BC 

AF 


-  A  two  byte  positive  number 

-  A  one  byte  positive  number 

-  A  one  byte  positive  quotient 

-  A  one  byte  positive  remainder  or  a  flag 
value  of  -I  on  overflow 

Again,  separate  8080  and  Z-80  versions  will  be  given. 

8080  Division  Subroutine 

DIVIDE:  PUSH  PSW  Save  registers 

PUSH  B 

PUSH  D 


3)     Inputs:  DIVDND 
DIVSOR 

Outputs:  (?OTENT 
RMANDR 


141 


LDED  DIVDND  Fetch  dividend  into  the  DE  register  pair 

LDA  DIVSOR  Fetch  divisor 

MOV  C,A  Save  in  register  C 

MVI  B,8  Loop  counter  in  register  B 

LOOP:      MOV  A,E  Shift  low  order  byte  to  the  left 

ANA  A  Clear  carry 

RAL  Shift 

MOV  E,A  Replace  value 

MOV  A,D  Fetch  high  order  byte 

RAL  Rotate  bringing  in  high  order  bit 

SUB  C  Subtract  divisor 

JP  SETBIT  If  result  was  positive,  jjmp 

ADD  C  Otherwise  add  back  divisor 

MOV  D,A  Replace  high  order  byte 

JMP  NEXT  Go  to  increment  phase 

SETBIT:  MOV  D,A  Replace  high  order  byte 

MOV  A,E  Fetch  low  order  byte 

ORI  1  Set  low  order  bit 

MOV  E,A  Replace  low  order  byte 

NEXT:      OCR  B  Decrement  loop  counter 

JNZ  LOOP  Repeat  until  done 

MOV  A,E  Quotient 

ANA  A  Test  sign  of  result 

JP  OK  If  positive,  the  result  is  accurate 

MVI  A,-l  Set  overflow  value 

STA  RMANDR 

JMP  DONE  Jump 

OK:         STA  QOTENT  Save  quotient 

MOV  A,D  Remainder 

STA  RMANDR  Save  remainder 

DONE:      POP  D  Restore  Registers 

POP  B 

POP  PSW 
RET 

Z-80  Division  Subroutine 

DIVIDE:  PUSH  AF  Save  registers 

PUSH  BC 

PUSH  DE 


142 


1  n 
LU 

r»r    f  n  i  \/nMn  ^ 
Ut,  \u  1  yUviU) 

Fetch  dividend  into  the  DE  register  pair 

LU 

n ,  V  U 1 V  oUK  ^ 

Fetch  divisor 

LD 

C,A 

Save  in  register  C 

LD 

B.8 

Loop  counter  in  register  B 

LD 

A,D 

Will  use  registers    A    and    E    as  a  pair 

uuring  TormaTion  ot  ine  quoTienT 

LUUr : 

C  1  A 

t 

Shift  low  order  byte 

KLA 

Rotate  high  order  byte  bringing  in  carry 

OUU 1  idC 1    0  t  V  1  bor 

JP 

P  SETBIT 

If   "i"hp   rp<^iili'  Wr^c:   noc:ii"i\/p  iiimn 

ADD 

A  C 

Jr 

NLXI 

Go  to  increment  phase 

bb 1 B 1 T : 

C  CT 
bt\ 

Set  low  order  bit 

NtX  1  : 

r\  1  M"7 
UJ  NZ 

LUUr 

Repeat  unti 1  done 

□  1  f 

-J  r— 

Test  sign  of  result 

JR 

If  positive,  the  result  is  accurate 

1  n 
LU 

A,-l 

Set  overflow  flag 

LD 

(KMANUK; , A 

ID 

JK 

UUNt 

J  ump 

uin: 

LU 

Save  rema  i  nder 

LD 

A  C 

A,E 

Quot  i  ent 

LD 

(vol  EN  1 ; ,A 

Save  quotient 

LXJNL : 

DAD 

rUr 

UE 

Restore  registers 

FOP 

BC 

POP 

AF 

RET 

Done 

4)    The  purpose  of  this  exercise  is  to  illustrate  coding  of  a  routine  where 
three  pointers  must  be  maintained.    Two  pointers  can  be  handled  easily 
using  the  DE  and  HL  pairs,  but  where  can  a  third  pointer  be  stored 
conveniently?    The  answer  is  to  use  the  top  of  the  stack.     Load  the 
first  pointer  into  HL  and  push  it  on  the  stack.     Load  the  second  and 
third  pointers  into  the  DE  and  HL  register  pairs.    Now  whenever  the 
first  pointer  is  needed  execute  an: 

XTHL  (8080) 

EX    (SP),HL  (Z-80) 
With  the  above  hint,  the  routine  should  be  within  the  grasp  of  the 
reader. 


143 


5)     Input:         WHERE    -    the  address  of  an  array  of  character 
DIGITS  -    the  number  of  characters  in  the  array 

Output:        RESULT  -    a  two  byte  binary  number  equal  to  the  value  input 

in  the  character  string 


e.g. 


WHERE 


31  30  30  31 


ASCII 

RESULT  =  0000  0000  0000  1001 


Separate  8080  and  Z-80  versions  will  be  given.  Both  will  call  a 
hypothetical  routine  named  WOOPS  if: 

a)  the  number  of  characters  as  recorded  in  DIGITS 
exceeds  16 

b)  any  character  appears  in  the  array  that  is  neither 
a  31  ^  or  a  30|_| 


8080 

Convert 

Binary  Input 

CBININ: 

PUSH 

PSW 

Save  registers 

PUSH 

B 

PUSH 

D 

PUSH 

H 

LDA 

DIGITS 

Fetch  number  of  characters 

CPI 

17 

Test  for  too  many 

CNC 

WOOPS 

If  a  carry  (borrow)  does  not  occur,  call 

t  WOOPS 

MOV 

B,A 

Save  DIGITS  as  a  counter 

1  HI  n 

nncir\u# 

OCT  poinier  to  cnaraCTer  array 

LXI 

D,0 

Clear  DE  register  to  use  in  forming  the 

resu 1 t 

LOOP: 

MOV 

A,M 

Fetch  character 

CPI 

30H 

Is  it  a  "0"? 

JZ 

OK 

Yes,  jump 

CPI 

31H 

Is  it  a  "1"? 

CNZ 

WOOPS 

If  not,  cal 1  WOOPS 

OK: 

RAR 

Shift  the  0  or  1  into  the  carry 

MOV 

A,E 

Fetch  low  order  byte  of  result 

RAL 

Rotate  digit  into  result 

MOV 

E,A 

Replace  low  order  byte 

MOV 

A,D 

Fetch  high  order  byte 

RAL 

Rotate  digit  into  result 

MOV 

D,A 

Replace  high  order  byte 

INX 

H 

Next  character 

DCR 

B 

Decrement  count 

JNZ 

LOOP 

Repeat  unti  i  done 

XCHG 

Swap  DE  and  HL 

144 


SHLD 

RESULT 

S+orG  final  result 

XCHG 

Swap  back 

POP 

H 

Restore  registers 

POP 

D 

POP 

B 

POP 

PSW 

RET 

Done 

Z-80 

Convert 

Binary  Input 

CBININ: 

PUSH 

AF 

Save  registers 

PUSH 

BC 

PUSH 

DE 

PUSH 

HL 

LD 

A, (DIGITS) 

Fetch  number  of  characters 

CP 

17 

Test  for  too  many 

CALL 

NC,WOOPS 

If  a  carry  (borrow)  does  not  occur. 

LD 

B,A 

Save  DIGITS  as  a  center 

LD 

HL, (WHERE) 

Set  pointer  to  character  array 

LD 

DE,0 

Clear  DE  register  to  use  in  forming 

LOOP: 

LD 

A, (HL) 

Fetch  character 

CP 

30H 

Is  it  a  "0"? 

JR 

Z,OK 

Yes,  jump 

CP 

31H 

Is  is  a  "1"? 

CALL 

NZ,WOOPS 

If  not,  cal 1  WOOPS 

OK: 

RRA 

Shift  the  0  or  1  into  the  carry 

RL 

E 

Rotate  digit  into  low  order  byte 

RL 

D 

Rotate  high  order  byte 

INC 

HL 

Next  character 

DJNZ 

LOOP 

Repeat  unt  i 1  done 

LD 

(RESULT), DE 

Store  final  result 

POP 

HL 

Restore  registers 

POP 

DE 

POP 

BC 

POP 

AF 

RET 

Done 

6)    a)    When  each  character  input  is  a  hexadecimal  digit,  you  will  want 

want  to  verify  that  each  character  in  the  buffer  lies  in  the  range 

a)  50^    <    Char    <    39^  (0-9) 

n     —  —  n 

b)  41^    <    Char    <    46^  (A-F) 

H     ~  —  n 

c)  61,,    <    Char    <    66,,  (a-f) 


145 


In  range    a,  you  will  naturally  subtract  30^. 

hi 


In  range  b,  a  subtraction  of  37|^  will  produce  the  appropriate 
hex  digit. 


In  range    c,  the  number  to  subtract  is  57  . 

H 

After  the  digit  has  been  isolated,   it  will  occupy  the  order  four 
bits  of  the  accumulator.     Shifting  those  bits  into  the  result 
should  pose  no  problem. 

b)     Input:        WHERE    -    the  address  of  the  character  array 

DIGITS  -    the  number  of  characters  in  the  array 

Output:      RESULT  -    a  two  byte  value  of  the  number 

During  the  course  of  the  subroutine,  it  will  be  necessary  to 
multiply  a  two  byte  value  by  10.  The  method  to  be  used  will 
be  to  multiply  the  high  and  low  order  bytes  separately.  The 
two  could  then  be  added  as: 


high  order  product 


low  order  product 


three  byte  result  | 


In  fact,  however,  if  the  high  order  byte  of  the  high  order 
product  is  non-zero,   it  will  be  time  to  call  WOOPS.    The  sum 
would  overflow  the  size  of  the  result. 


8080 


Decimal  to  Binary  Input  Subroutine 


DECBIN:  PUSH 
PUSH 
PUSH 
PUSH 
LDA 
CP  I 

CNC 

MOV 

LHLD 

LXI 


PSW 

B 
D 
H 

DIGITS 
6 

WOOPS 

B,A 

WHERE 

D,0 


Save  registers 


Fetch  number  of  digits 

The  largest  signed  number  that  will  fit  is 
32,767 

Call   if  more  than  five  digits  (this  still 
won't  guarantee  no  overflow) 

Save  count 

Load  address  of  character  array 
Clear  DE  register  for  the  result 


146 


LOOP: 


MOV 
CPI 

cc 

SUI 
MOV 


A,M 

30H 

WOOPS 

30H 

C,A 


Fetch  character 
Is  it  under  30H? 
Yes,  ca I  I  WOOPS 

The  digit  must  be  OK,  subtract 

To  get  its  binary  value,  save  in  C.  We 
now  need  to  multiply  the  result  already 
forming  by  10.     This  will  be  done  in  two 
separate  operations. 


Mnu 

a  F 

M,t 

rsTc^n    low  ur  uci    uy  i  g 

o  1  n 

Ml TPMD 

mil  I"f"Ir\  1  i/^^nH 
O  1  Ui  c            iMU  II  1  p  1  1  CaflU 

MM  1 
nv  1 

n,  1  10 

o  1  n 

Ml  TPI  D 
ML  1 r LK 

\  (n             rrtiil"^ir>l  i£ir" 

oTOi  6    1  %J  Ob  iTiu  1  r  1  p  1  I  er 

OnLL 

Ml  TDI  V 
HL  1  rLT 

rnuiTipiy  Tne.  two 

A  n 

rciv-ii  niyii  oiutJi  uyio 

OWap  ut  anu  riL 

LHLD 

PRODCT 

Re+ch  result 

XCHG 

Swap  back 

STA 

MLTCND 

Store  high  order  as  multiplicand 

CALL 

MLTPLY 

Multiply  by  same  multiplier 

LDA 

PRODCT+ 1 

High  order  byte 

ANA 

A 

Test  for  zero 

CNZ 

WOOPS 

If  it  isn't,  cal 1  WOOPS 

LDA 

PRODCT 

Low  order  byte 

ADD 

D 

Add  to- high  order  of  previous  product 

CO 

WOOPS 

1 f  overf low,  ca 1 1  WOOPS 

MUV 

n  A 
U,  A 

Place  result  in  low  order 

MOV 

A,C 

Fetch  new  digit 

ADD 

E 

Add  to  low  order 

MUV 

C  A 

t,A 

Replace  low  order 

MM  T 

Clear    A    without  destroying  flags 

u 

nOQ  in  any  carry  irom  low  oraer 

IT  overriow,  ca i i  nvurj 

MOV 

D,A 

Replace  high  order 

I  NX 

H 

To  point  to  next  digit 

DCR 

B 

Decrement  count 

JNZ 

LOOP 

Repeat  unt i 1  done 

XCHG 

Swap  OE  and  HL 

SHLD 

RESULT 

Store  result 

POP 

H 

Restore  registers 

POP 

D 

POP 

B 

POP 

PSW 

RET 

Done 

147 


LOOP: 


"7  Qfft 

Dec  i  ma  1  +o 

Binary  Input  Subroutine 

A  C 

Ar 

Save  registers 

Dl  1 C  U 

rUbn 

DP 

PI  IQU 

ut 

Dl  ICU 

ML 

LD 

A, (DIGITS) 

Fetch  number  of  digits 

CP 

6 

The  largest  signed  number  that  will  fit  is  32, 

CALL 

NC,WOOPS 

Call   if  more  than  five  digits  (this  still  won' 
yuaranxee  no  overiiow.^ 

1  n 

R  A 

oave  couni 

LU 

111      f  U/UCTDC  ^ 

HL, IWntKt; 

Load  address  of  character  array 

1  n 
LU 

Ut,  iO 

Clear  DE  register  for  the  result 

1  n 

LU 

A    f  MM 
n,  ^ riL  1 

reicn  cnaracTer 

PD 

IS  IT  unoer  jioni 

1  1 

P    WPPD  c 

0, WUUro 

Yes,  ca 1 1  wuurb 

PD 
Or 

AU 

IS  IT  over  jyn I 

CALL 

NC,WOOPS 

Yes,  cal 1  WOOPS 

SUB 

30H 

The  digit  must  be  OK,  subtract 

LO 

C,A 

to  get  its  binary  value,  save  in    C,    We  now 
need  to  multiply  the  result  already  forming  by 
10,    This  wi 1 1  be  done  in  two  separate  operatii 

1  n 
LU 

A,t 

Fetch  low  order  byte 

LU 

/  kxi  Tr'Mn  \  A 
KrAL  1  LNU  J  ,A 

Store  as  multiplicand 

1  n 
LU 

A     1  01 

A,  1 10 

1  n 
LU 

1  Ml  TPI  D  ^  A 
\ ML  1 r LK  J , A 

oTore  110  as  muiTipi  ler 

P  A  1  1 

OnLL 

Ml  TPI  V 
riL  1  r  L  I 

Multiply  the  two 

1  n 

LU 

A  n 
n,  U 

rexcn  nign  oraer  oyxe 

LU 

UC  f  \  rvtoUL  1  } 

reicn  resu i t 

1  n 

LU 

(MLTCND),A 

Store  high  order  as  multiplicand 

PA  1  1 

MLTPLY 

Multiply  by  same  multiplier 

1  n 

LU 

A,  (RESULT+DHIgh  order  byte 

AMD 

A 

Test  for  zero 

PA  1  1 

NZ,WOOPS 

If  it  isn't,  cal 1  WOOPS 

1  n 
LU 

A, (RESULT) 

Low  order  byte 

Ann 
nUU 

A,D 

Add  to  high  order  of  previous  product 

PA  1  1 

PE,WOOPS 

If  overflow,  cal 1  WOOPS 

LU 

D,A 

Place  result  in  low  order 

1  n 
LU 

C 

Fetch  new  digit 

Ann 
nuu 

A,E 

Add  to  low  order 

LD 

E,A 

Replace  low  order 

LD 

A,0 

Clear    A    without  destroying  flags 

ADC 

A,D 

Add  in  any  carry  from  low  order 

148 


CALL  PE,WOOPS        If  overflow,  call  WOOPS 

LD  D,A  Replace  high  order 

INC  HL  To  point  to  next  digit 

DJNZ  LOOP  Decrement  Count 

Repeat  unt  i  I  done 

LD  (RESULT), DE  Store  result 

POP  HL  Restore  registers 

POP  DE 

POP  BC 

POP  AF 

RET  Done 


7)    Translating  back  from  binary  to  character  should  pose  no  problems  in 

the  case  of  binary  and  hexadecimal  values.    The  algorithm  for  converting 
back  from  binary  into  decimal   is  a  little  trickier.    The  trick  is  to 
divide  the  two  byte  value  by  10  and  use  the  remainder  as  the  lowest 
order  digit.     Then  divide  what's  left  of  the  result  by  10  again  and 
so  on,  so  that  the  character  value  is    created  from  right  to  left. 
The  only  problem  is  that  you  are  very  likely  to  get  an  overflow  on  the 
first  division.    How  can  you  break  the  division  into  two  pieces  to 
get  around  this  problem? 


A  CASUAL  INTRODUCTION  TO  DATA  STRUCTURES 

I)    Due  to  the  machine  dependent  aspects  of  I/O,   it  is  not  possible  to 
present  a  routine  that  is  guaranteed  to  work  on  your  system.  The 
routine  called  KYBDIN  that  accepts  a  single  character  from  the 
keyboard  and  leaves  its  value  in  the  accumulator.    Echoing  is 
accomplished  by  calling  a  hypothetical  routine  called  VIDOUT  which 
accepts  a  single  character  in  the  accumulator  and  displays  it  on 
the  screen.     It  is  assumed  that  this  routine  does  not  destroy  the 
contents  of  the  accumulator. 


8080 

Str i  ng 

1  nput 

Routi  ne 

BUFFER: 

.BLKB 

30 

Reserve  30  bytes  of  storage 

STRGIN: 

PUSH 

PSW 

Save  registers 

PUSH 

B 

PUSH 

H 

LXI 

H, BUFFER 

Set  HL  to  point  to  the  buffer 

MVI 

A,20H 

ASCII  for  a  space 

MVI 

B,30 

Number  of  characters  in  buffer 

CLRLOP: 

MOV 

M,A 

Clear  buffer  location 

INX 

H 

Next  buffer  location 

149 


DCR  B  Decrement  count 

JNZ  CLRLOP  Repeat  until  entire  buffer  cleared 

LXI  H, BUFFER  Reset  pointer  to  start  of  buffer 

MVI  B,30  Overflow  counter 

INLOOP:    CALL  KYBDIN  Get  character 

CALL  VIDOUT  Echo 

CPI  0DH  Carriage  return? 

JZ  DONE  Yes,  jump  out  of  loop 

MOV  M,A  Else,  store  in  buffer 

INX  H  Next  buffer  location 

DCR  B  Overflow  counter 

JNZ  INLOOP  Repeat  if  not  full 

DONE:        POP  H  Restore  registers 

POP  B 

POP  PSW 

RET  Done 

Z-80  String  Input  Rout  i  ne 

BUFFER:   .BLKB  30  Reserve  30  bytes  of  storage 

STRGIN:    PUSH  AF  Save  registers 

PUSH  BC 

PUSH  DE 

PUSH  HL 

LD  A,20H  ASCII  for  a  space 

LD  (BUFFER), A  Clear  first  character 

LD  HL, BUFFER  Pointer  to  first  character 

LD  DE,BUFFER+1       Pointer  to  second  character 

LD  BC,29  Number  of  characters  to  be  cleared 

LDIR  Clear  buffer 

LD  B,30  Overflow  counter 

INLOOP:    CALL  KYBDIN  Get  character 

CALL  VIDOUT  Echo 

CO  0DH  Carriage  return? 

JR  Z,DONE  Yes,  jump  out  of  loop 

LD  (HL),A  Otherwise,  store  character 

INC  HL  Next  buffer  location 

DJNZ  INLOOP  Repeat  until  full  or  carriage  return 

DONE:        POP  HL  Restore  registers 

POP  DE 

POP  BC 

POP  AF 

RET  Done 


150 


2)    See  note  to    exercise  #1.    The  subroutine  below  uses  VIDOUT. 
INPUT:      WHERE      -    start  address  of  the  buffer 
COUNT      -    number  of  characters 


8080         String  Output  Routine 

STROUT:    PUSH  PSW  Save  registers 

PUSH  B 

PUSH  H 

LHLD  WHERE  Fetch  start  address 

LDA  COUNT  Fetch  number  of  characters 

MOV  B,A  Save  count 

OUTLOP:    MOV  A,M  Fetch  character 

CALL  VIDOUT  Output  to  screen 

INX  H  Next  character 

OCR  B  Decrement  count 

JNZ  OUTLOP  Repeat  until  done 

POP  H  Restore  registers 

POP  B 

POP  PSW 

RET  Done 

Z-80  String  Output  Routine 

STROUT:    PUSH  AF  Save  registers 

PUSH  BC 

PUSH  HL 

LD  HL, (WHERE) Fetch  start  address 

LD  A, (COUNT)  Fetch  number  of  characters 

LD  B,A  Save  count 

OUTLOP:    LD  A,(HL)  Fetch  character 

CALL  VIDOUT  Output  to  screen 

INC  HL  Next  character 

DJNZ  OUTLOP  Decrement  count,  repeat  unti I  done 

POP  HL  Restore  registers 

POP  BC 

POP  AF 

RET  Done 


3)    The  driver  will  be  a  simple  matter  of  moving  data  and  calling  STROUT 
and  STRGIN  if  the  data  is  structured  carefully.    When  you  know  in 


151 


advance  the  exact  message  you  want  output,  define  it  in  ASCII  in 
your  data  area.    Count  up  the  length  and  store  it  as  a  constant  as 
well.    The  driver  routine  will  be  trivial   if  the  data  is  defined  as 
follows  (use  the  keywords  your  assembler  wants  to  see): 


Mbbi : 

A  COT  T 

Name: 

Mbbz  : 

A  COT  T 

Address : 

MSG3: 

.ASCII 

"Phone  number?" 

LENl 

.BYTE 

5 

LEN2: 

.BYTE 

8 

LEN3: 

.BYTE 

13 

NAME: 

.BLKB 

20 

ADDRSS: 

.BLKB 

30 

PHONE: 

.BLKB 

8    (the  extra  character 

4)    The  storage  area  can  be  reserved  using: 

. LOC  2000    (or  some  page  boundry  address) 

POOL:  .BLKB  400H 

a )           8080  Link-up  Subroutine 

LINKUP:  PUSH  PSW 

PUSH  B  Save  registers 

PUSH  D 

PUSH  H 

LXI  H,POOL  Start  address  of  space 

SHLD  AVAIL  Avail  will  point  to  first  node 

LXI  D,P00L+64  DE  will  point  to  next  node 

LXI  B,127  BC=(node  size*2)  -1  (the  reason  should  become  clear  late 

MVI  A, 15  The  number  of  nodes  that  will  fit  minus  1. 

SETLOP:  MOV  M,E  Low  order  byte  of  link 

INX  H  Point  to  next  byte 

MOV  M,D  High  order  byte  of  link 

DAD  B  To  point  to  the  node  after  next 

XCHG  Now  HL  points  to  the  next  node 

DCR  A  Decrement  loop  counter 

JNZ  SETLOP  Repeat  until  all  nodes  have  link  fields  set  but  the  last 

MOV  M,A  Set  final   I i nk  va I ue  of  a  I  I  0' s 

INX  H 

MOV  M,A 

POP  H  Retore  registers 

POP  D 


152 


POP  B 

POP  PSW 

RET  Done 

Z-80  Link-up  Subroutine 

LINKUP:  PUSH  AF 

PUSH  BC  Save  registers 

PUSH  DE 

PUSH  HL 

LD  HL,POOL  Start  address  of  space 

LD  (AVAIL),HL  Avail  will  point  to  first  node 

LD  DE,P00L+64  DE  will  point  to  next  node 

LD  BC,127  BC=(node  size*2)  -1  (the  reason  should  become  clear  later) 

LD  A, 15  The  number  of  nodes  that  will  fit  minus  1 

SETLOP:  LD  (HL),E  Low  order  byte  of  link 

INC  HL  Point  to  next  byte 

LD  (HL),D  High  order  byte  of  link 

ADD  HL,BC  To  point  to  the  node  after  next 

EX  DE,HL  Now  HL  points  to  the  next  node 

DEC  A  Decrement  loop  counter 

JR  NZ, SETLOP  Repeat  until  all  nodes  have  link  fields  set  but  the  last 

LD  (HL),A  Set  final   link  value  of  all  0's 

INC  HL 

LD  (HL),A 

POP  HL  Restore  registers 

POP  DE 

POP  BC 

POP  AF 

RET  Done 

b)           8080  Get-node  Subroutine 

GETNOO:  PUSH  PSW  Save  registers 

PUSH  D 

LHLD  AVAIL  Fetch  pointer  to  next  available  node 

MOV  A,L  Test  for  all  zeroes  which  would  indicate  no  more 

ORA  H  nodes  available 

CZ  OVFLOW  Call  hypothetical  overflow  routine  if  no  nodes  are  left 

MOV  E,M  Otherwise  fetch  link  field  from  this  node 

INX  H 

MOV  D,M 

XCHG  Swap  DE  +  HL 

SHLD  AVAIL  Set  new  pointer  in  avail 


153 


XCHG  Swap  back  so  HL  points  to  new  node 

POP  D  Restore  registers 

POP  PSW 

RET  Done 


Z-80  Get-node  Subroutine 

GETNOD:  PUSH  AF  Save  registers 

PUSH  DE 

LD  HL, (AVAIL)  Fetch  pointer  to  next  available  node 

LD  A,L  Test  for  all  0's  which  would  indicate  no  more  nodes 

OR  H  available 

CALL  Z,OVFLOW  Call  hypothetical  overflow  routine  if  no  nodes  are 

LD  E,(HL)  Otherwise  fetch  link  field  from  this  node 

INC  HL 

LD  D, (HL) 

LD  (AVAIL),DE  Set  new  pointer  in  avail 

POP  DE  Restore  registers 

POP  AF 

RET  Done 


c)    Since  there  are  no  overflow  worries,  this  routine  should  pose  no 
problems.    A  basic  attack  might  involve: 

1)  fetch  value  of  avail   (pointer  to  next  node  on  avail  list) 

2)  store  that  pointer  in  link  field  of  node  to  be  returned 

3)  store  pointer  to  returned  node  in  avail 


BINARY  CODED  DECIMAL  ARITHMETIC 

I)    The  method  to  be  used  involves  two  separate  subroutines.    The  first 
subroutine  will  accept  a  pointer  to  a  buffer  which  contains  only 
digits  in  character  form  and  will  translate  from  left  to  right  into 
BCD.    The  second  subroutine  will  analyze  the  original  raw  input 
extracting  punctuation  and  stray  characters.     It  will  then  call  the 
first  and  pass  it  the  byte  count  and  address  in  register    B    and  the 
DE  register  pair  respectively.    The  final  BCD  number  will  be  placed 
in  an  array  called  NUMBER,    The  first  three  bytes  of  NUMBER  will  be 
its  descriptor  block. 


8080  Digit  to  BCD  Subroutine 

DGTBCD:  PUSH  PSW  Save  registers 

PUSH  B 

PUSH  D 


154 


PUSH 

H 

LXI 

H  NUMBER+3 

F  i  r^^i"  dp«;1' i        i  on   c;ln+  for  RPH 

LDAX 

FpiT"  h  rl  i  n  i  + 

I    ^  1       1  1      VJ  1  ^  1  1 

SUI 

30H 

nplpfa  ASriT  rndp 

RAL 

Ro't'3't'P   f  ril  1  r   +  i  npc;   +o   +  hta    1  o "f  + 

PAI 

RAL 

PAL 

MOV 

r  A 

JO  VC 

I  NX 

n 

L/ 

Po  i  n+   +0   npv+  H  ?  o i  + 

LDAX 

D 

Fp+p  h  npyi"  ri  i  n  i  + 

1    ^IV^II      IIC^)       Ul^l  1 

SUI 

30H 

np  1  P+p  A*^PTT  roHp 

ADD 

c 

Tn   form  RPD  n?^  i  r  nf  Hini+c 

MOV 

M,A 

Savp    i  n  niimhpr* 

INX 

0 

Npyf"  H  i  n  i  + 

INX 

H 

Nlpyi"  hv+p   in  niimhpr 

1               1        L/  y    1  w        1  II      1  1  U 1 1 1 L/  w  1 

DCR 

B 

Dpprpmpn't'  hv+p  ("niiiTt" 

L^^VaV  1     S>^l  1          III           Lf  Y     1    C        NirV/U  III 

JNZ 

LOOP 

Rpnpa+  unl"  i  1  donp 

POP 

H 

Restore  rea  i  s+ers 

POP 

D 

POP 

B 

POP 

PSW 

RET 

Done 

Z-80      Digit  to  BCD  Subroutine 


Unlike  the  8080  version.  This  subroutine  affects  the  contents 
of  the  buffer  location  passed  to  it. 

Save  registers 


LOOP: 


PUSH 

AF 

PUSH 

BC 

PUSH 

DE 

PUSH 

HL 

LD 

HL, NUMBER+3 

SUB 

A 

EX 

DE,HL 

RRD 

LD 

(DE),A 

INC 

HL 

RRD 

EX 

DE,HL 

RLD 

INC 

HL 

Pointer  to  output  area 
Clear  accumulator 

Swap  pointers  so  HL  points  to  input  buffer 

Bring  in  binary  form  of  first  digit 

Store  i  n  number 

Next  character 

Bring  in  binary  fomi 

Swap  pointers  to  HL  points  to  number 

Rotate  second  digit  into  number 

Next  byte 


155 


INC  DE  Next  digit 

DJNZ  LOOP  Repeat  until  done 

POP  HL  Restore  registers 

POP  DE 

POP  BC 

POP  AF 

RET  Done 


The  second  subroutine  deals  with  data  areas  defined  as  on  page  143. 
The  sizes  of  BUFFER  and  NUMBER  can  be  assumed  to  have  been  defined 
to  be  large  enough  to  accomodate  any  number  the  routine  will  have 
to  deal  with.    That  is, the  routine  needn't  do  any  overflow  error 
checking.    We  will  also  assume  that  the  entire  data  area  for  NUMBER 
was  previously  cleared. 


8080     Characters  to  Digits  Subroutine 


CARTDG:  PUSH 
PUSH 
PUSH 
PUSH 
SUB 
STA 
LXI 
LXI 

PRESIG:  LDAX 
CPI 
JZ 
CPI 
JZ 
CPI 
JZ 
CPI 
JNZ 
MVI 
STA 
J  MP 

NOMNUS:  CPI 
JNZ 
I  NX 
J  MP 


PSW 

B 

D 

H 

A 

SPRFLG 
H, BUFFER 
D, BUFFER 
D 

20H 

I  NCR 

24H 

I  NCR 

2BH 

INCR 

2DH 

NOMNUS 
A, -I 

NUMBER+2 

INCR 

2EH 

NOPERD 
D 

POSTDC 


Clear  accumulator 
Clear  spare  flag 
Pointer  to  Buffer  +  0 
Same 

Fetch  character 
Is  it  a  space? 
Yes ,  j  ump 
Is  it  a  "$"? 
Yes,  jump 
Is  it  a  "+"? 
Yes,  jump 
Is  it  a  "-"? 
No,  jump 

Set  negative  indicator 
Place  in  sign  byte 
J  ump 

Is  it  a  "."? 
No,  jump 
Next  character 
Jump 


156 


CP  I 

30H 

Is  it  less  than  a  digit? 

JC 

TERMSG 

Yes,  jump 

CPI 

3AH 

Is  it  greater  than  a  digit? 

JNC 

TERMSG 

Yes.  iumo 

MOV 

M,A 

store  character 

INX 

D 

Increment  buffer  pointers 

I  NX 

H 

INX 

B 

Increment  digit  count 

J  MP 

POSTSG 

1 1  imn 

INX 

D 

Next  character 

J  MP 

PRESIG 

Repeat 

etc. 


So  the  whole  routine  is  .just  a  straightforward  coding  of  the  algorithm  on 
pages  143-146.    NOTE:    Do  not  call  D6TBCD  when  the  number  is  zero  bytes  long. 

Z-80      Characters  to  Digits  Subroutine 
CARTDG:  PUSH  AF 

PUSH  BC 


PUSH 

DE 

PUSH 

HL 

SUB 

A 

Clear  accumulator 

LD 

{SPRFLG),A 

Clear  spare  flag 

LD 

HL, BUFFER 

Pointer  to  Buffer  +  0 

LD 

DE, BUFFER 

Same 

PRESIG:  LD 

A,(DE) 

Fetch  character 

CP 

20H 

Is  it  a  space? 

JR 

Z,INCR 

Yes,  jump 

CP 

24H 

Is  is  a  "$"? 

JR 

Z,INCR 

Yes,  jump 

CP 

2BH 

Is  it  a  "+"? 

JR 

Z,INCR 

Yes,  jump 

CP 

2DH 

Is  it  a  "-"? 

JR 

NZ, NOMNUS 

No,  jump 

LD 

A,-l 

Set  negative  indicator 

LD 

(NUMBER+2),A 

Place  in  sign  byte 

JR 

I  NCR 

J  ump 

NOMNUS:  CP 

2EH 

Is  it  a  "."? 

JR 

NZ,NOPERD 

No,  jump 

INX 

D 

Next  character 

JP 

POSTDC 

Jump 

157 


INWr  tKU : 

_>)0n 

Is  it  less  than  a  digit? 

i  P 

Yes,  jump 

Is  it  greater  than  a  digit? 

IP 

Or 

TeS|  jump 

LU 

f  HI  ^  A 

Store  character 

UC 

1 ncremenT  DUTrer  poinTers 

INC 

HI 

INP 

R 

1  Mvi  dnc?M  1    u  1  y  1  1    v^L'uii  1 

JP 

POSTSG 

Jump 

INCR: 

INC 

DE 

Next  character 

JR 

PRESIG 

Repeat 

etc. 

So  the  whole  routine  is  just  a  straightforward  coding  of  the  algorithm  on 
pages  143-146.    NOTE:    Do  not  call  DGTBCD  when  the  number  is  zero  bytes  long 


2)    Fixed  point  addition; 
INPUT:  VARA 
VARB 
SZMAX 

OUTPUT:  SUM 


-    are  two  BCD  numbers 


number  of  bytes  of  storage  reserved  for  each 
number  input 

data  area  where  result  will  be  stored  or  flag 
result  of  negative  zero  on  overflow 


8080 


Fixed  Point  Addition 


SUM:  .BLKB 
ENDSUM: .BLKB 
BLXKA:  .BLKB 
BLOCKB: .BLKB 
FXPTAD:  PUSH 
PUSH 
PUSH 
PUSH 
LXI 
LXI 
MVI 

FXPT05:  MOV 
STAX 
I  NX 
I  NX 


H,VARA 
B,3 

A,M 

D 
H 
D 


(for  max  of  256  byte  number  and  3  byte  descript 
(storage  area  for  descriptor  blocks  of  input) 
Save  registers 


258 
1 
3 
3 

PSW 
B 
D 
H 

D,BLCX2KA       Pointer  to  block  save  area 


Pointer  to  descriptive  block 
Number  of  bytes  in  block 
Transfer  block  to  block  save  area 


158 


DCR  B 

JNZ  FXPT05 

MVI  B,3  Bytes  in  second  block 

LXI  H,VARB  Pointer  to  second  descriptive  block  (DE  already  points 

to  second  save  area) 

FXPT10:  MOV  A,M  Transfer  second  block  to  save  area 

STAX  D 

I  NX  H 

I  NX  D 

DCR  B 

JNZ  FXPT10 

LDA  SZMAX  Fetch  maximum  size 

MOV  C,A  Save 
(ALIGN  DECIMAL  POINT) 

LDA  VARB+1  Number  of  decimal  places  in  VARB 

MOV  B,A  Save 

LDA  VARA+1  Number  of  decimal  places  in  VARA 

SUB  B  Find  the  difference 

MOV  D,A  Save 

JZ  FXPT30  Jump  if  same  number  of  places 

JNC  FXPT25  Jump  if    A    has  more 

LXI  H,VARA  Pointer  to  size  of  VARA 

FXPT15:  ADD  M  Get  new  size 

CMP  C  Compare  to  maximum  size 

JZ  FXPT20  If  same,  we're  OK 

CNC  OVFLOW  If  over  max,  call  overflow 

FXPT20:  MOV  M,A  Store  new  size 

MOV  A,D  Restore  difference 

INX  H  Pointer  to  decimal  places  in  variable 

ADD  M  New  decimal  places 

MOV  M,A  Store  new  decimal  places 

STA  SUM+1  Store  decimal  places  in  sum 

JMP  FXPT30  Jump 

FXPT25:  LXI  H,VARB  Pointer  to  size  of  VARB 

JMP  FXPT15  Get  new  size 

(CHECK  SIGN  OF  NUMBERS) 

FXPT30:  LDA  VARB+2  Sign  of  VARB 

MOV  B,A  Save 

LDA  VARA+2  Sign  of  VARA 

CMP  B  Do  signs  match? 

JNZ  FXPT35  No,  jump 

STA  SUMf2  Give  their  common  sign  to  the  result 


159 


LXI 

H,VARA 

Pass  the  parameters  to  BCD  ADD 

SHLD 

ADDl 

LXI 

H,VARB 

SHLD 

ADD2 

LXI 

H,SUM 

SHLD 

RESULT 

CALL 

BCDADD 

Add  the  two  numbers 

J  MP 

FXPT55 

FXPT35: 

LDA 

VARB 

Size  of  VARB 

MOV 

B,A 

Save 

LDA 

VARA 

Size  of  VARA 

CMP 

B 

Are  numbers  the  same  size? 

JNZ 

FXPT45 

No ,  j  ump 

LX 1 

D, VARA+j 

First  byte  of  number  of  VARA 

LX  1 

H, vAKd+^ 

r 1 rsT  DyTe  ot  numoer  ot  vnKd 

r XPT40 : 

LDAX 

D 

Fetch  byte  of  VARA 

CMP 

M 

Compare  to  VARB,  same? 

JNZ 

FXPT45 

No,  jump 

INX 

D 

Yes,  then  check  next  byte 

1  NX 

H 

DCR 

B 

JNZ 

FXPT40 

Repeat  while  bytes  remain 

SUB 

A 

The  two  numbers  are  equal,  so  move  ; 

zero  to  sum 

STA 

SUM 

STA 

SUM+1 

STA 

SUM+2 

J  MP 

\t  I'll 

FXPT55 

FXPT45: 

JC 

FXPT50 

Jump  if  VARB  is  larger 

LDA 

VARA+2 

STA 

SUM+2 

LXI 

H,VARA 

Prepare  parameters  to  subtract 

VARB 

from  VARA 

SHLD 

NMUEND 

LXI 

H,VARB 

SHLD 

SBTRHD 

LXI 

H,  SUM 

SHLD 

DFFRNC 

CALL 

BCDSUB 

Subtract 

J  MP 

J  I'll 

FXPT55 

1   /\l     1  -/ 

FXPT50: 

LDA 

VARBT2 

STA 

SUM+2 

LXI 

H,VARB 

Prepare  parameters  to  subtract 

VARA 

from  VARB 

SHLD 

MNUEND 

LXI 

H,  VARA 

SHLD 

SBTRHD 

LXI 

H,SUM 

SHLD 

DFFRNC 

160 


CALL  BCDSUB 

FXPT55:      .  The  routine  is  essentially  complete,  Just 

rnove  the  descriptive  blocks  back  from  the  save 
area,  pop  the  registers,  and  return. 

 Z-80  Fixed  Point  Addition  

SUM:      .BLKB  258  (for  max  of  255  byte  number  and  3  byte  descriptor  block) 

ENDSUMr.BLKB  1 

BLOCKA:  3  (storage  area  for  descriptor  blocks  of  input) 

BLOCKS:  3 

FXPTAD:  PUSH  AF  Save  registers 

PUSH  BC 

PUSH  DE 

PUSH  HL 

LD  DE,BLXKA  Pointer  to  block  save  area 

LD  HL,  VARA  Pointer  to  descriptive  block 

LD  BC,3  Number  of  bytes  in  block 

LOIR  Transfer  block  to  block  save  area 

LD  BC,3  Bytes  in  second  block 

LD  HL,VARB  Pointer  to  second  descriptive  block  (DE  already  points 

to  second  save  area) 

LDIR  Transfer  second  block  to  save  area 

LD  A,(SZMAX)  Fetch  maximum  size 

LD  C,A  Save 

(ALIGN  DECIMAL  POINT) 

LD  A, (VARB+1)  Number  of  decimal  places  in  VARB 

LD  B,A  Save 

LD  A,(VARA+1)  Number  of  decimal  places  in  VARA 

SUB  B  Find  the  difference 

LD  D,A  Save 

JR  Z,FXPT20  Jump  if  same  number  of  places 

JP  NC,FXPT15  Jump  if    A    has  more 

LD  H,VARA  Pointer  to  size  of  VARA 

FXPT05:  ADD  A,(HL)  Get  new  size 

CP  C  C^pare  to  maximum  size 

JR  Z,FXPT10  If  same,  we're  OK 

CALL  NC,OVFLOW  If  over  max,  call  overflow 

FXPT10:  LD  (HL),A  Store  new  size 

LD  A,D  Restore  difference 

INC  HL  Pointer  to  decimal  places  in  variable 

ADD  A,(HL)  New  decimal  places 

LD  (HL),A  Store  new  decimal  places 


161 


LD  (SUNH-1),.A      Store  decimal  places  in  sum 

JP  FXPT20  Jump 

FXPT15:  LD  HL,VARB         Pointer  to  size  of  VARB 

JP  FXPT05          Get  new  size 

(CHECK  SIGN  OF  NUMBERS) 

FXPT20:  LD  A,(VARB+2)     Sign  of  VARB 

LD  B,A  Save 

LD  A,(VARA+2)    Sign  of  VARA 

CP  B                  Do  sings  match? 

JR  NZ,FXPT25      No,  jump 

LD  (SUM+2),A      Give  their  common  sign  to  the  result 

LD  HL,  VARA       Pass  the  parameters  to  BCD  ADD 

LD  (ADD11,HL 

LD  HL,VARA 

LD  (ADD2),HL 

LD  HL,SUM 

LD  (RESULT), HL 

CALL  BCDADD          Add  the  two  numbers 

JP  FXPT45 

FXPT25:  LD  A, (VARB)        Size  of  VARB 

LD  B,A  Save 

LD  A, (VARA)        Size  of  VARA 

CP  B                  Are  numbers  the  same  size? 

JR  NZ,FXPT35      No,  jump 

LD  DE,VARA+3      First  byte  of  number  of  VARA 

LD  HL,VARB+3      First  byte  of  number  of  VARB 

FXPT30:  LD  A,(DE)           Fetch  byte  of  VARA 

CP  (HL)              Compare  to  VARB,  same? 

JR  NZ,FXPT35      No,  jump 

INC  DE                Yes,  then  check  next  byte 

INC  HL 

DJNZ  FXPT30 

SUB  A                  The  two  numbers  are  equal,  so  move  zero  to  sum 

LD  (SUM), A 

LD  (SUM+1),A 

LD  (SUMf2),A 

JR  FXPT45 

FXPT35:  JP  C,FXPT40       Jump  if  VARB  is  larger 

LD  A,(VARA+2) 

LD  (SUM+2),A 

LD  HL,VARA        Prepare  parameters  to  subtract  VARB  from  VARA 

LD  (MNUEND),HL 

LD  HL.VARA 


162 


FXPT40: 


FXPT45: 


LD 

(SBTRHD),HL 

LD 

HL,SUM 

LD 

(DFFRNC),HL 

CALL 

BCDSUB 

JR 

FXPT45 

LD 

A,(VARB+2) 

LD 

(SUM+2) ,A 

LD 

HL,VARB 

LD 

(MNUEND) ,HL 

LD 

HL,VARA 

1  n 

^QRTDI-in^  l-ll 
\  OD  1  KnU  ^  )  rIL 

LD 

HL,SUM 

LD 

(DFFRNC),HL 

CALL 

BCDSUB 

Subtract 


Prepare  parameters  to  subtract  VARA  from  VARB 


The  routine  is  essentially  complete.  Just  move  the 
descriptive  blocks  back  from  the  save  area,  pop  the 
registers,  and  return. 


The  two  routines  BCDADD  and  BCDSUB  are  extremely  simple.  They  are  just 
multibyte  addition  and  subtraction  with  decimal  adjust  between  each  add 
or  subtract.    BCDSUB  should  squeeze  out  any  leading  00  bytes  before  returning. 


3)    The  fixed  point  subtract  is  trivial  once  the  fixed  point  add  has  been 
written.    The  algorithm  follows: 

a)  load  and  save  the  sign  of  the  subtrahend 

b)  reverse  the  sign  in  the  descriptor  block 

c )  ca I  I  FXPTAD 

d)  replace  the  original  sign 


4)    A  portion  of  the  floating  point  multiply  subroutine  will  be  given  here. 
What  will  not  be  shown  is: 

a)  initially  saving  the  registers  and  the  descriptor  blocks  of 
MLTPLR  and  MLTCND  and  clearing  PRODCT. 

b)  adding  the  two  numbers  of  digits  to  the  right  of  the  decimal 
point  and  storing  it  in  the  descriptor  block  of  the  result 

c)  determining  which  number  is  longer.    Placing  a  pointer  to  the 
end  of  the  shorter  in  the  HL  register  pair  placing  the  size  of 
the  shorter  in  the    C  register 

d)  determining  the  sign  of  the  result  and  storing  it 

e)  restoring  registers  and  descriptor  blocks 

What  will  be  shown  is  performing  the  mul tipl icatlon  itself  using  calls 
to  BCDADD. 


163 


8080         Floating  Point  Multiply 


rrMUL 1 : 

• 
• 
• 

XCHG 

Swap  DE  and  HL 

LXI 

H,MLTCND 

Set  up  parameters  for  BCDADD 

SHLD 

ADDl 

LXI 

H,PRODCT 

SHLD 

ADD2 

SHLD 

RESULT 

i.e.,  ADD2-«-ADDl  +  ADD2 

XCHG 

Swap  back 

BIGLP: 

MOV 

A,M 

Fetch  byte  of  multiplier 

ANI 

0FH 

Clear  high  order  digit 

JZ 

LILP2A 

MOV 

B,A 

Save  as  counter 

LILPl: 

CALL 

BCDADD 

Add  multiplicand  a  single  time 

DCR 

B 

Decrement  counter 

JNZ 

LILPl 

Repeat  addition  the  number  of  times  of  the  digit 

LILP2A: 

CALL 

LFTSFT 

Shift  number  4  bits  to  left  for  multiply  by  10 

MOV 

A,M 

Get  byte  again 

ANI 

JZ 

RRC 

0F0H 
LILP4 

Clear  low  order  digit 
Rotate  four  times 

RRC 

RRC 

RRC 

MOV 

B,A 

Save  as  counter 

LI  LPS: 

CALL 

BCDADD 

Add  multiplicand  a  single  time 

XR 

B 

Decrement  counter 

JNZ 

LILP2 

Repeat  addition  the  number  of  times  of  the  digit 

LILP4: 

CALL 

RGTSFT 

1_    •    ^  1             11                            i_                  iii»i__t__i_l                   •!     1         /    •                          i_  1 

Shifts  the  number  4  bits  to  the  right  (i.e.,  back 
to  original  alignment)  and  adds  a  00  byte  to  the 
end.    This  accomplishes  a  second  4  bit  shift  to 
the  left  without  having  the  number  move  through 
memory  by  more  than  one  byte. 

DCX 

H 

[iexf  byte  of  multiplier 

DOR 

C 

Decrement  byte  count 

JNZ 

• 
• 
• 

BIGLP 

Repeat  unti 1  done 

Z-80 

Floating  Point 

Mu 1 1  i  p  1  y 

FPMULT: 

• 
• 

• 

SUB 

A 

Clear  accumulator 

164 


LD 

HL,MLTCND 

Set  up  parameters  for  BCDADD 

LD 

(ADD1),HL 

LD 

HL,PRODCT 

LD 

(ADD2),HL 

LD 

(RESULT), HL 

i.e.,  ADD2^ADD2  +  ADDl 

BIGLP: 

RRD 

Fetch  first  digit 

LD 

B,A 

Save  as  counter 

LILPl: 

CALL 

BCDADD 

Add  multipl icand 

DJNZ 

LILPl 

Repeat  the  number  of  times  of  the  digit 

CALL 

LFTSFT 

Shift  number  4  bits  1o  left  for  multiply  by  10 

RRD 

Fetch  second  digit 

LD 

B,A 

Save  as  counter 

LILP2: 

CALL 

BCDADD 

Add  mu 1 1  i  p 1 i  cand 

DJNZ 

LILP2 

Repeat  the  number  of  times  of  the  digit 

CALL 

RGTSFT 

Shifts  the  number  4  bits  to  the  right  (i.e.,  back 
to  original  alignment)  and  adds  a  00  byte  to  the 
end.    This  accomplishes  a  second  4  bit  shift  to 
ine  leiT  wiinouT  naving  tug  numuer  move  inrougn 
memory  by  more  than  one  byte 

INC 

HL 

Next  byte  of  multiplier 

DEC 

C 

Decrement  byte  count 

JR 

• 
• 

NZ, BIGLP 

Repeat  unti 1  done 

5)    Floating  point  division  will  again  make  use  of  LFTSFT  and  RGTSFT  to 
prevent  the  dividend  from  wandering  through  memory.     It  will  also  save 
and  later  restore  the  descriptor  blocks  of  the  dividend  and  divisor. 
It  will  have  to  call  the  fixed  point  subtract  subroutine  rather  than 
BCDSUB,  because  the  sign  of  the  result  is  not  known  beforehand. 


165 


index 


Accumulator,  14,  31 
ACT,  32,  106 

ADC,  32,  41,  106,  108 

ADD,  32,  40,  41,  106,  108 
Addition,  8,  9,  32,  40,  41 
Address,  15,  17 

ADI,  32,  106 
ANA,  34,  107 
AND,  11,  33,  34,  107 
ANI.  34,  107 
Arithmetic,  31 
Array,  72,  80 
ASCII,  68,  113 
Available  nodes,  78 

Binary,  4-6 

Binary  coded  decimal,  83 
Bit.  7 

BIT,  58,  109 
Bit  manipulation,  57 
Block  search,  79 
Block  transfer,  79 
Body,  44 
Boolean,  10 
Borrow,  9 

Boundary  alignment,  76 
Byte,  7 

CALL,  52,  53,  110,  111 
Carry  flag,  9,  10,  12 
CC,  53,  110 
CCD,  80,  106 
CCDR,  80,  106 
CCF,  39,  107 
CCI.  80,  106 
CCIR,  80.  106 
Clock  speed,  101 
CM,  53,  1 1 1 
CM  A,  39.  107 
CMC,  39.  107 


CMP,  37,  107 
CNC,  53,  111 
CNO,  53,  111 
CNZ.  53.  110 
CO.  53,  111 
Compare,  34 

Complement  accumulator,  38 

Complement  carry,  39 

Conditional  jump,  44 

Con\ersions,  5 

CP,  37.  53,  107,  111 

CPD,  80,  106 

CPDR,  80,  106 

CPE,  53,  111 

CPI,  37.  80.  106,  107 

CPIR,  80,  106 

CPL.  39.  107 

CPO,  53,  111 

CZ,  53,  1 1 1 

DAA,  85,  107 
DAD,  40,  108 
DADC,  41,  108 
DADX,  41,  108 
DADY,  41,  108 
DCR,  38,  107 
DCX.  40,  108 
DEC,  38,  40,  107,  108 
Decimal,  5.  6 
Decimal  adjust,  84 
Declaration,  71 
Decrement,  37 
DI,  107 
Digits,  4,  6 
Displacement,  21,  75 
Division,  62 
DJNZ.  50,  110 
Documentation.  98 
DSBC,  41,  108 


166 


Index 


EI,  107 

LDDR,  79,  106 

Fouate  74 

LDED  '^4  104 

X~^                               X^  y                      X    J           1    V/  X 

EX  27  28  105  106 

LDI  79  106 

EXAF  28  105 

LDIR  79  106 

X^  X  XX  J        §    mj  y        A  \/  \J 

Exchanjie  26 

LHLD,  24,  104 

Exclusive  OR  1*^  83 

I  inkpH  striirt iirp^  77 

X~<I  I  1  ^  V.  vX    0LiUv.LL11^0)     /  1 

EXX  '^8  105 

LIXD  ''4  104 

^    ■  X  ^  X  X^  t      ^    I  y        X   \J  X 

LIYD,  24,  105 

Flags  31  32 

LSPD  24  105 

X  iKj  X    X_^  J             X  J      A  \y  «^ 

LXI  24  104 

Hexadecimal,  4—6 

Load  17  22 

I  offiral  3 1 

IM,  108 

Loop,  44,  50 

Immediate  20  24 

IN,  111 

Magnitude  bits,  7,  10 

IXC  38  40  107  108 

\femorv   1  5 

Inrrement  37  44  4'i 

\rpmorv-reffister  18  22 

IND,  112 

^Mnemonics  17 

A  *  A  A  ft        A  ft  A  V-/  ft  ft  ft  ^^4^  y       ft  f 

Index  register  21 

^fofliilnr  Droeramminir  51  52 

i  ■  ft  V/ V  ft  V«  1  t-ft  ■         L.^  ft  \J         ft  U  ftftliftftftft  ft  ft  >^  t      V-^   ft    f      \J  ^ 

INDR.  1 12 

\fonitor  6Q 

INI.  1 12 

MOV  104 

INIR.  112 

^riilti-dimensional  arrav.  72 

A  *  1  LX  li,l    \.ftllll\.ftft>Jl  \J  1  ft  U  X     U  ft  ft  U  T  y  f 

Initialization,  44 

Multiplication,  60 

INP,  1 1 1 

MVI  104 

A  *  X    T    X  y      X  V/  X 

INR  38  107 

INX  40  108 

NEC  39  107 

1,  ^  X^  X^  «          ^  <      1  V  1 

Neeate  39 

TC  47  110 

Nibble  7 

TM  47  110 

NOP  40  107 

ft  ^            X    f       X  ^/  y       ft  # 

IMP  47  109 

NOT  38 

TMPR  49  110 

Number  svstein  4 

1^  UlllL^^l      ij  T  (J    V>  IIX  f  X 

INC  47  110 

T\0  47  110 

One's  romnlement  8 

V    1  I  \_   .}      \j  111      AV-iiiv.  ftft  y 

TNZ  47  110 

OR  11  33  107 

v^ft.^f     ft  ftf    \^  %^  f    ft  9 

TO  47  110 

OR  A  34  107 

V  ^  XX.i   Xf      %J   A  y       M  \J  t 

TP  47  109  110 

IXf      Iff     IV^v^j  liV/ 

ORI  34  107 

TPE.  1 10 

OTDR.  1 12 

JPO.  1 10 

OTIR.  1 12 

TR  49  110 

OUT.  1 12 

TRC  49  110 

1    XX              ,         I   mJ  ^         11  \J 

OITTD  112 

V  ^            X    X  y  ^  11^ 

TRNC  49  110 

OITTDR  112 

X^  V       X    A,j^  X  X  «      ft   1  ^ 

TRNZ  49  110 

1  XX  A  ^  X^  f       1        f       11  \J 

OUTI,  112 

TRZ  49  110 

1    1  X  X^  1       1        •       11  V/ 

OrTIR,  112 

TZ  47  109 

Ol'TP.  112 

Overflow  flae  9  10 

I  RC  D  104 

I  D  17-''l  ''3  '>A  104  IOt 

Paee  76 

LDA  ''0  104 

Parity  flair  P 

M                        11  ftft  f-^  1  1 

LDAI.  104 

Patch.  100 

LD.AR.  104 

PCHL.  .50.  110 

LD.AX.  19,  104 

PCIX.  51,  110 

LDD,  79,  106 

PCIY,  51,  110 

168 


Z-89  and  8989  Assembly  Language  Programming 


POP,  25,  26,  111 

SHLD,  24,  105 

Post-test,  45 

Sign,  12 

Pre-test,  45 

Sign  bit,  7,  10 

Program  counter,  15,  16,  22,  43 

Signed  compare,  35,  36 

PUSH,  25,  26,  105 

SIXD,  24,  105 

SIYD,  24,  105 

RAL,  59,  108 

SLA,  67,  109 

RALR,  66,  109 

SLAR.  67,  109 

RAR,  59,  108 

SPHL,  23,  105 

RARR,  66,  109 

SPIX,  23,  105 

RC,  54,  111 

SPIY,  23,  105 

Register,  14 

SRA.  67,  109 

Register  indirect  jump,  50 

SRAR,  67,  109 

Register  pair,  15 

SRL,  67.  109 

Relative  jump,  47,  48 

SRLR,  67,  109 

RES,  58,  109 

SSPD,  24.  105 

RET,  54.  Ill 

ST  A.  20.  104 

RETI.  Ill 

Stack.  16 

RETN,  111 

Stack  pointer,  15,  22,  25 

RL.  66.  109 

STAI.  104 

RLA.  59.  108 

STAR.  104 

RLC.  59.  66.  108 

ST  AX.  104 

RLCA,  59.  108 

STC,  107 

RLCR.  66.  108 

Structure,  73 

RLD.  68.  109 

Structured  programming,  52 

RM.  54.  Ill 

SUB,  33,  106,  107 

RNC.  54.  Ill 

Subroutine,  51,  52 

RNO.  54,  111 

Subtraction.  9,  33,  40,  41 

RNZ.  54.  Ill 

SUI,  33.  107 

RO.  54,  111 

Swapped  format,  23 

Rotate,  59,  66,  68 

RP.  54.  Ill 

T-state,  101 

RPE,  54,  111 

Test,  45,  46 

RPO,  54,  111 

Top  down,  98 

RR.  66.  109 

Two's  complement,  7 

RRA.  59.  108 

RRC.  59.  66,  108.  109 

Unsigned  compare,  37 

RRCA.  o9,  108 

Utility,  69 

RRCR,  66.  109 

RRD,  68.  109 

Value,  17 

RST.  Ill 

RZ,  54,  111 

Variable,  14,  71,  75 

SBB,  33,  107 

XCHG,  27,  105 

SBC,  33,  41,  107,  108 

XRA,  34,  107 

SBCD.  24,  105 

XRI,  34,  107 

SBI,  33,  107 

XOR,  12,  33,  107 

SCF,  39,  107 

XTHL,  27,  106 

SDED,  24,  105 

XTIX,  27,  106 

SET,  58,  109 

XTIY,  27,  106 

Set  carry,  39 

Shift,  59,  66.  67 

Zero  flag,  12 

HOBBY  WORLD 


N2  6113 


Date 


19511  Business  Center  Drive 
Northridge,  Ca.  91324 

CALL  TOLL  FREE:  (800)-423-5387 
CA,  HI,  AK:  (213)  886-9200 


Name 


Address 


City/State/Zip 


Phone 


Sold  by 

COD 

Cash 

Check 

Chg. 

Acct. 

New 

Code 

J 

Source 


Qty 

Cat.  No. 

Description 

Unit  Price 

Total 

v 

el 

Ship  Via  Tax 

Shipping 
TOTAL 

C, 

All  returns  must  be  accompanied  by  this  receipt. 


5167-0 

$7.95     Z-80  AND  8080  ASSEMBLY  LANGUAGE 
PROGRAMMING 

Kathe  Spracklen 

Here  is  the  first  book  that  gives  you  an  introductory  look  at 
assembly  language  programming  for  the  Z-80  and  8080  pro- 
cessors. It  is  intended  to  provide  just  about  everything  the 
applications  programmer  needs  to  know  to  get  the  most  out 
of  his  or  her  machine.  Programming  techniques  are  presented 
along  with  the  instructions.  Numerous  diagrams  and  examples 
are  provided.  Exercises,  with  answers,  are  included  with  each 
chapter,  making  it  ideal  for  self-study  and  for  schools. 

Other  Books  of  Interest . . . 
SARGON:  A  Computer  Chess  Program 

Dan  and  Kathe  Spracklen 

This  is  the  computer  chess  program  that  won  first  prize  in  the 
chess  tournament  at  the  1978  West  Coast  Computer  Faire. 
Available  in  book  form  (#5155-7,  paper,  120  pages)  or  on 
computer  program  tapes  for  the  TRS-80  Level  II  (#00603)  and 
Apple  II-24K  (#00604)  machines. 

BASIC  BASIC:  An  Introduction  to  Computer 
Programming  in  BASIC  Language,  Second  Edition 

and 

ADVANCED  BASIC:  Applications  and  Problems 

Both  by  James  S.  Coan 

Two  books  that  give  you  the  complete  picture  of  the  BASIC 
language.  One  introduces  the  language;  the  other  offers  ad- 
vanced techniques  and  applications.  Basic  BASIC,  #5106-9, 
paper,  #5107-7,  cloth,  288  pages;  Advanced  BASIC,  #5855-1, 
paper,  #5856-X,  cloth,  192  pages 

BASIC  MICROPROCESSORS  AND  THE  6800 

Ron  Bishop 

Two  valuable  books  in  one:  an  introduction  to  microproces- 
sors for  the  beginner,  and  a  complete  description  of  the  M6800 
system  for  the  engineer.  #0758-2,  paper,  272  pages 

THE  6800  MICROPROCESSOR:  A  Self-Study  Course 
with  Applications 

Lance  A.  Leventhal 

A  simple  introduction  to  the  6800  microprocessor,  including 
15  laboratory  exercises  that  emphasize  the  control  applica- 
tions of  microcomputers.  #5120-4,  paper,  112  pages 


HAYDEN  BOOK  COMPANY,  INC. 
Rochelle  Park,  New  Jersey 


ISBN  0-81 04-61 67-0